diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2012-12-31 20:40:34 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2012-12-31 21:35:11 +0100 |
commit | 9d07cb1b2cfee55390de0194db9052530a73a0c2 (patch) | |
tree | db94cfbe4cc117dbb523d34525400994b9699e5d /kernel_drivers |
initial commit
Diffstat (limited to 'kernel_drivers')
85 files changed, 98158 insertions, 0 deletions
diff --git a/kernel_drivers/Kconfig b/kernel_drivers/Kconfig new file mode 100644 index 0000000..2f7b88a --- /dev/null +++ b/kernel_drivers/Kconfig @@ -0,0 +1,17 @@ +choice + prompt "Vivante GPUs" + depends on ARCH_DMW + default GPU_VIVANTE_V4 + optional + +config GPU_VIVANTE_V2 + boolean "Version 2.x" + +config GPU_VIVANTE_V4 + boolean "Version 4.x" + +endchoice + +source "drivers/gpu/vivante/v2/Kconfig" +source "drivers/gpu/vivante/v4/Kconfig" + diff --git a/kernel_drivers/Makefile b/kernel_drivers/Makefile new file mode 100644 index 0000000..dbafd97 --- /dev/null +++ b/kernel_drivers/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_GPU_VIVANTE_V2) += v2/ +obj-$(CONFIG_GPU_VIVANTE_V4) += v4/ diff --git a/kernel_drivers/v2/Kconfig b/kernel_drivers/v2/Kconfig new file mode 100644 index 0000000..93204b4 --- /dev/null +++ b/kernel_drivers/v2/Kconfig @@ -0,0 +1,21 @@ +if GPU_VIVANTE_V2 + +menu "Vivante Options" + +config GPU_VIVANTE_ANDROID + bool + default y if ANDROID + default n + +config GPU_VIVANTE_DEBUG + boolean "Enable debug output" + +config GPU_VIVANTE_PROFILER + boolean "Enable profiler" + +config GPU_VIVANTE_NEWSIGNAL + boolean "Use new linux signal" + +endmenu + +endif diff --git a/kernel_drivers/v2/Makefile b/kernel_drivers/v2/Makefile new file mode 100644 index 0000000..fd82023 --- /dev/null +++ b/kernel_drivers/v2/Makefile @@ -0,0 +1,73 @@ +# +# Makefile for Vivante GPU driver + +debug = 0 +profiler = 0 +newsignal = 0 + +ifeq ($(CONFIG_GPU_VIVANTE_DEBUG),y) + debug = 1 +endif + +ifeq ($(CONFIG_GPU_VIVANTE_PROFILER),y) + profiler = 1 +endif + +ifeq ($(CONFIG_GPU_VIVANTE_NEWSIGNAL),y) + newsignal = 1 +endif + +# +# driver options +# +ccflags-y += -DENUM_WORKAROUND=0 +#ccflags-y += -DFLARE_ON + +ccflags-y += -DDBG=$(debug) +ccflags-$(CONFIG_GPU_VIVANTE_DEBUG) += -DDEBUG -D_DEBUG + +#ccflags-y += -DNO_DMA_COHERENT +ccflags-y += -DENABLE_ARM_L2_CACHE=0 +#ccflags-y += -DCONFIG_DOVE_GPU=1 +ccflags-y += -DgcdNO_POWER_MANAGEMENT=0 +ccflags-y += -DUSE_PLATFORM_DRIVER=1 +ccflags-y += -DVIVANTE_PROFILER=$(profiler) +ccflags-y += -DENABLE_GPU_CLOCK_BY_DRIVER=1 +ccflags-y += -DUSE_NEW_LINUX_SIGNAL=$(newsignal) +ccflags-y += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=0 +ccflags-y += -DgcdkREPORT_VIDMEM_USAGE=0 + +ifeq ($(CONFIG_GPU_VIVANTE_ANDROID),y) + ccflags-y += -DANDROID=1 +endif + +# +# driver includes +# +ccflags-y += \ + -I$(obj)/hal/inc \ + -I$(obj)/hal/kernel \ + -I$(obj)/hal/user \ + -I$(obj)/arch/XAQ2/hal/kernel + +# +# driver module name +# +obj-$(CONFIG_GPU_VIVANTE_V2) += galcore.o + +# +# driver objects +# +galcore-objs += \ + hal/os/linux/kernel/gc_hal_kernel_debug.o \ + hal/os/linux/kernel/gc_hal_kernel_device.o \ + hal/os/linux/kernel/gc_hal_kernel_driver.o \ + hal/os/linux/kernel/gc_hal_kernel_linux.o \ + hal/os/linux/kernel/gc_hal_kernel_os.o \ + hal/kernel/gc_hal_kernel.o \ + hal/kernel/gc_hal_kernel_command.o \ + hal/kernel/gc_hal_kernel_event.o \ + hal/kernel/gc_hal_kernel_heap.o \ + hal/kernel/gc_hal_kernel_mmu.o \ + hal/kernel/gc_hal_kernel_video_memory.o \ + arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.o diff --git a/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c b/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c new file mode 100644 index 0000000..d8ae1c0 --- /dev/null +++ b/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c @@ -0,0 +1,3859 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal.h" +#include "gc_hal_kernel.h" + +#define _GC_OBJ_ZONE gcvZONE_HARDWARE + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +static gceSTATUS +_IdentifyHardware( + IN gckOS Os, + OUT gceCHIPMODEL * ChipModel, + OUT gctUINT32_PTR ChipRevision, + OUT gctUINT32_PTR ChipFeatures, + OUT gctUINT32_PTR ChipMinorFeatures0, + OUT gctUINT32_PTR ChipMinorFeatures1, + OUT gctUINT32_PTR ChipMinorFeatures2 + ) +{ + gceSTATUS status; + gctUINT32 chipIdentity; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00018, &chipIdentity)); + + /* Special case for older graphic cores. */ + if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))))) + { + *ChipModel = gcv500; + *ChipRevision = ( ((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) ); + } + + else + { + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00020, + (gctUINT32_PTR) ChipModel)); + + /* !!!! HACK ALERT !!!! */ + /* Because people change device IDs without letting software know + ** about it - here is the hack to make it all look the same. Only + ** for GC400 family. Next time - TELL ME!!! */ + if ((*ChipModel & 0xFF00) == 0x0400) + { + *ChipModel &= 0x0400; + } + + /* Read CHIP_REV register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00024, ChipRevision)); + + if ((*ChipModel == gcv300) + && (*ChipRevision == 0x2201) + ) + { + gctUINT32 date, time; + + /* Read date and time registers. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x00028, &date)); + + gcmkONERROR( + gckOS_ReadRegister(Os, 0x0002C, &time)); + + if ((date == 0x20080814) && (time == 0x12051100)) + { + /* This IP has an ECO; put the correct revision in it. */ + *ChipRevision = 0x1051; + } + } + } + + /* Read chip feature register. */ + gcmkONERROR( + gckOS_ReadRegister(Os, 0x0001C, ChipFeatures)); + + /* Disable fast clear on GC700. */ + if (*ChipModel == gcv700) + { + *ChipFeatures = ((((gctUINT32) (*ChipFeatures)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + if (((*ChipModel == gcv500) && (*ChipRevision < 2)) + || ((*ChipModel == gcv300) && (*ChipRevision < 0x2000)) + ) + { + /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */ + *ChipMinorFeatures0 = 0; + *ChipMinorFeatures1 = 0; + *ChipMinorFeatures2 = 0; + } + else + { + /* Read chip minor feature register #0. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00034, + ChipMinorFeatures0)); + + *ChipMinorFeatures0 = ((((gctUINT32) (*ChipMinorFeatures0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) << (0 ? 27:27))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) << (0 ? 27:27))); + + if (((((gctUINT32) (*ChipMinorFeatures0)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) + ) + { + /* Read chip minor featuress register #1. */ + gcmkONERROR( + gckOS_ReadRegister(Os, + 0x00074, + ChipMinorFeatures1)); + + /* Read chip minor featuress register #1. */ +#if defined GC_MINOR_FEATURES2_Address + gcmkONERROR( + gckOS_ReadRegister(Os, + GC_MINOR_FEATURES2_Address, + ChipMinorFeatures2)); +#else + /* Chip doesn't has minor features register 2. */ + *ChipMinorFeatures2 = 0; +#endif + } + else + { + /* Chip doesn't has minor features register #1 or 2. */ + *ChipMinorFeatures1 = 0; + *ChipMinorFeatures2 = 0; + } + } + + *ChipMinorFeatures0 = ((((gctUINT32) (*ChipMinorFeatures0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) << (0 ? 27:27))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) << (0 ? 27:27))); + + /* Success. */ + gcmkFOOTER_ARG("*ChipModel=%x *ChipRevision=%x *ChipFeatures=0x%08x " + "*ChipMinorFeatures0=0x%08X *ChipMinorFeatures1=0x%08x " + "*ChipMinorFeatures2=0x%08x", + *ChipModel, *ChipRevision, *ChipFeatures, + *ChipMinorFeatures0, *ChipMinorFeatures1, + *ChipMinorFeatures2); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_GetChipSpecs( + IN gckHARDWARE Hardware + ) +{ + gctUINT32 streamCount = 0; + gctUINT32 registerMax = 0; + gctUINT32 threadCount = 0; + gctUINT32 shaderCoreCount = 0; + gctUINT32 vertexCacheSize = 0; + gctUINT32 vertexOutputBufferSize = 0; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + if (((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) + { + gctUINT32 specs; + + /* Read gcChipSpecs register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00048, &specs)); + + /* Handy macro to improve reading. */ +#define gcmSPEC_FIELD(field) \ + ( ((((gctUINT32) (specs)) >> (0 ? GC_CHIP_SPECS_field)) & ((gctUINT32) ((((1 ? GC_CHIP_SPECS_field) - (0 ? GC_CHIP_SPECS_field) + 1) == 32) ? ~0 : (~(~0 << ((1 ? GC_CHIP_SPECS_field) - (0 ? GC_CHIP_SPECS_field) + 1)))))) ) + + /* Extract the fields. */ + streamCount = ( ((((gctUINT32) (specs)) >> (0 ? 3:0)) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1)))))) ); + registerMax = ( ((((gctUINT32) (specs)) >> (0 ? 7:4)) & ((gctUINT32) ((((1 ? 7:4) - (0 ? 7:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:4) - (0 ? 7:4) + 1)))))) ); + threadCount = ( ((((gctUINT32) (specs)) >> (0 ? 11:8)) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1)))))) ); + shaderCoreCount = ( ((((gctUINT32) (specs)) >> (0 ? 24:20)) & ((gctUINT32) ((((1 ? 24:20) - (0 ? 24:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:20) - (0 ? 24:20) + 1)))))) ); + vertexCacheSize = ( ((((gctUINT32) (specs)) >> (0 ? 16:12)) & ((gctUINT32) ((((1 ? 16:12) - (0 ? 16:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:12) - (0 ? 16:12) + 1)))))) ); + vertexOutputBufferSize = ( ((((gctUINT32) (specs)) >> (0 ? 31:28)) & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1)))))) ); + } + + /* Get the stream count. */ + Hardware->streamCount = (streamCount != 0) + ? streamCount + : (Hardware->chipModel >= gcv1000) ? 4 : 1; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: streamCount=%u%s", + Hardware->streamCount, + (streamCount == 0) ? " (default)" : ""); + + /* Get the vertex output buffer size. */ + Hardware->vertexOutputBufferSize = (vertexOutputBufferSize != 0) + ? 1 << vertexOutputBufferSize + : (Hardware->chipModel == gcv400) + ? (Hardware->chipRevision < 0x4000) ? 512 + : (Hardware->chipRevision < 0x4200) ? 256 + : 128 + : (Hardware->chipModel == gcv530) + ? (Hardware->chipRevision < 0x4200) ? 512 + : 128 + : 512; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexOutputBufferSize=%u%s", + Hardware->vertexOutputBufferSize, + (vertexOutputBufferSize == 0) ? " (default)" : ""); + + /* Get the maximum number of threads. */ + Hardware->threadCount = (threadCount != 0) + ? 1 << threadCount + : (Hardware->chipModel == gcv400) ? 64 + : (Hardware->chipModel == gcv500) ? 128 + : (Hardware->chipModel == gcv530) ? 128 + : 256; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: threadCount=%u%s", + Hardware->threadCount, + (threadCount == 0) ? " (default)" : ""); + + /* Get the number of shader cores. */ + Hardware->shaderCoreCount = (shaderCoreCount != 0) + ? shaderCoreCount + : (Hardware->chipModel >= gcv1000) ? 2 + : 1; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: shaderCoreCount=%u%s", + Hardware->shaderCoreCount, + (shaderCoreCount == 0) ? " (default)" : ""); + + /* Get the vertex cache size. */ + Hardware->vertexCacheSize = (vertexCacheSize != 0) + ? vertexCacheSize + : 8; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexCacheSize=%u%s", + Hardware->vertexCacheSize, + (vertexCacheSize == 0) ? " (default)" : ""); + + /* Get the maximum number of temporary registers. */ + Hardware->registerMax = (registerMax != 0) + ? 1 << registerMax + : (Hardware->chipModel == gcv400) ? 32 + : 64; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: registerMax=%u%s", + Hardware->registerMax, + (registerMax == 0) ? " (default)" : ""); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +****************************** gckHARDWARE API code ***************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckHARDWARE_Construct +** +** Construct a new gckHARDWARE object. +** +** INPUT: +** +** gckOS Os +** Pointer to an initialized gckOS object. +** +** OUTPUT: +** +** gckHARDWARE * Hardware +** Pointer to a variable that will hold the pointer to the gckHARDWARE +** object. +*/ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + OUT gckHARDWARE * Hardware + ) +{ + gckHARDWARE hardware = gcvNULL; + gceSTATUS status; + gceCHIPMODEL chipModel; + gctUINT32 chipRevision; + gctUINT32 chipFeatures; + gctUINT32 chipMinorFeatures0; + gctUINT32 chipMinorFeatures1; + gctUINT32 chipMinorFeatures2; + gctUINT16 data = 0xff00; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); + + /* Enable the GPU. */ + gcmkONERROR(gckOS_SetGPUPower(Os, gcvTRUE, gcvTRUE)); + gcmkONERROR(gckOS_WriteRegister(Os, 0x00000, 0)); + + /* Identify the hardware. */ + gcmkONERROR(_IdentifyHardware(Os, + &chipModel, + &chipRevision, + &chipFeatures, + &chipMinorFeatures0, + &chipMinorFeatures1, + &chipMinorFeatures2)); + + /* Allocate the gckHARDWARE object. */ + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(struct _gckHARDWARE), + (gctPOINTER *) &hardware)); + + /* Initialize the gckHARDWARE object. */ + hardware->object.type = gcvOBJ_HARDWARE; + hardware->os = Os; + + /* Set chip identity. */ + hardware->chipModel = chipModel; + hardware->chipRevision = chipRevision; + hardware->chipFeatures = chipFeatures; + hardware->chipMinorFeatures0 = chipMinorFeatures0; + hardware->chipMinorFeatures1 = chipMinorFeatures1; + hardware->chipMinorFeatures2 = chipMinorFeatures2; + hardware->powerBaseAddress = ( (chipModel == gcv300) + && (chipRevision < 0x2000) + ) ? 0x100 : 0x00; + hardware->powerMutex = gcvNULL; + + /* Get chip specs. */ + gcmkONERROR(_GetChipSpecs(hardware)); + + /* Determine whether bug fixes #1 are present. */ + hardware->extraEventStates = ((((gctUINT32) (chipMinorFeatures1)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))); + + /* Check if big endian */ + hardware->bigEndian = (*(gctUINT8 *)&data == 0xff); + + /* Initialize the fast clear. */ + gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1)); + + /* Set power state to ON. */ + hardware->chipPowerState = gcvPOWER_ON; + hardware->broadcast = gcvFALSE; + hardware->settingPowerState = gcvFALSE; + + hardware->lastWaitLink = ~0U; + + gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex)); + + /* Return pointer to the gckHARDWARE object. */ + *Hardware = hardware; + + /* Success. */ + gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (hardware->powerMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex)); + } + + if (hardware != gcvNULL) + { + gcmkVERIFY_OK(gckOS_Free(Os, hardware)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Destroy +** +** Destroy an gckHARDWARE object. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Destroy the power mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex)); + + /* Mark the object as unknown. */ + Hardware->object.type = gcvOBJ_UNKNOWN; + + /* Free the object. */ + gcmkONERROR(gckOS_Free(Hardware->os, Hardware)); + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_InitializeHardware +** +** Initialize the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 baseAddress; + gctUINT32 chipRev; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the chip revision register. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + 0x00024, + &chipRev)); + + if (chipRev != Hardware->chipRevision) + { + /* Chip is not there! */ + gcmkONERROR(gcvSTATUS_CONTEXT_LOSSED); + } + + /* Disable isolate GPU bit. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (0x00000100)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))))); + + /* Reset memory counters. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0003C, + ~0U)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0003C, + 0)); + + /* Get the system's physical base address. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + /* Program the base addesses. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x0041C, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00418, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00420, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00428, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + 0x00424, + baseAddress)); + +#if !VIVANTE_PROFILER && 1 + { + gctUINT32 data; + + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00100, + &data)); + + /* Enable clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + + if ((Hardware->chipRevision == 0x4301) + || (Hardware->chipRevision == 0x4302) + ) + { + /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2 + ** revisions. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); + } + + gcmkONERROR(gckOS_WriteRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00100, + data)); + + /* Disable PE clock gating on revs < 5.0 when HZ is present without a + ** bug fix. */ + if ((Hardware->chipRevision < 0x5000) + && ((((gctUINT32) (Hardware->chipMinorFeatures1)) >> (0 ? 9:9) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) + && ((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) + ) + { + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00104, + &data)); + + /* Disable PE clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + Hardware->powerBaseAddress + + 0x00104, + data)); + } + } +#endif + + /* Test if MMU is initialized. */ + if ((Hardware->kernel != gcvNULL) + && (Hardware->kernel->mmu != gcvNULL) + ) + { + /* Reset MMU. */ + gcmkONERROR( + gckHARDWARE_SetMMU(Hardware, + Hardware->kernel->mmu->pageTableLogical)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryMemory +** +** Query the amount of memory available on the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * InternalSize +** Pointer to a variable that will hold the size of the internal video +** memory in bytes. If 'InternalSize' is gcvNULL, no information of the +** internal memory will be returned. +** +** gctUINT32 * InternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctUINT32 * InternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctSIZE_T * ExternalSize +** Pointer to a variable that will hold the size of the external video +** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the +** external memory will be returned. +** +** gctUINT32 * ExternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * ExternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * HorizontalTileSize +** Number of horizontal pixels per tile. If 'HorizontalTileSize' is +** gcvNULL, no horizontal pixel per tile will be returned. +** +** gctUINT32 * VerticalTileSize +** Number of vertical pixels per tile. If 'VerticalTileSize' is +** gcvNULL, no vertical pixel per tile will be returned. +*/ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (InternalSize != gcvNULL) + { + /* No internal memory. */ + *InternalSize = 0; + } + + if (ExternalSize != gcvNULL) + { + /* No external memory. */ + *ExternalSize = 0; + } + + if (HorizontalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *HorizontalTileSize = 4; + } + + if (VerticalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *VerticalTileSize = 4; + } + + /* Success. */ + gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x " + "*InternalAlignment=0x%08x *ExternalSize=%lu " + "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x " + "*HorizontalTileSize=%u *VerticalTileSize=%u", + gcmOPT_VALUE(InternalSize), + gcmOPT_VALUE(InternalBaseAddress), + gcmOPT_VALUE(InternalAlignment), + gcmOPT_VALUE(ExternalSize), + gcmOPT_VALUE(ExternalBaseAddress), + gcmOPT_VALUE(ExternalAlignment), + gcmOPT_VALUE(HorizontalTileSize), + gcmOPT_VALUE(VerticalTileSize)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryChipIdentity +** +** Query the identity of the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gceCHIPMODEL * ChipModel +** If 'ChipModel' is not gcvNULL, the variable it points to will +** receive the model of the chip. +** +** gctUINT32 * ChipRevision +** If 'ChipRevision' is not gcvNULL, the variable it points to will +** receive the revision of the chip. +** +** gctUINT32 * ChipFeatures +** If 'ChipFeatures' is not gcvNULL, the variable it points to will +** receive the feature set of the chip. +** +** gctUINT32 * ChipMinorFeatures +** If 'ChipMinorFeatures' is not gcvNULL, the variable it points to +** will receive the minor feature set of the chip. +** +** gctUINT32 * ChipMinorFeatures1 +** If 'ChipMinorFeatures1' is not gcvNULL, the variable it points to +** will receive the minor feature set 1 of the chip. +** +** gctUINT32 * ChipMinorFeatures2 +** If 'ChipMinorFeatures2' is not gcvNULL, the variable it points to +** will receive the minor feature set 2 of the chip. +** +*/ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gceCHIPMODEL * ChipModel, + OUT gctUINT32 * ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures, + OUT gctUINT32* ChipMinorFeatures1, + OUT gctUINT32* ChipMinorFeatures2 + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Return chip model. */ + if (ChipModel != gcvNULL) + { + *ChipModel = Hardware->chipModel; + } + + /* Return revision number. */ + if (ChipRevision != gcvNULL) + { + *ChipRevision = Hardware->chipRevision; + } + + /* Return feature set. */ + if (ChipFeatures != gcvNULL) + { + gctUINT32 features = Hardware->chipFeatures; + + if (( ((((gctUINT32) (features)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Override fast clear by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->allowFastClear) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + if (( ((((gctUINT32) (features)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )) + { + /* Override compression by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (Hardware->allowCompression) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); + } + + /* Mark 2D pipe as available for GC500.0 through GC500.2 and GC300, + ** since they did not have this bit. */ + if (( (Hardware->chipModel == gcv500) + && (Hardware->chipRevision <= 2) + ) + || (Hardware->chipModel == gcv300) + ) + { + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); + } + + *ChipFeatures = features; + } + + /* Return minor feature set. */ + if (ChipMinorFeatures != gcvNULL) + { + *ChipMinorFeatures = Hardware->chipMinorFeatures0; + } + + /* Return minor feature set 1. */ + if (ChipMinorFeatures1 != gcvNULL) + { + *ChipMinorFeatures1 = Hardware->chipMinorFeatures1; + } + + /* Return minor feature set 2. */ + if (ChipMinorFeatures2 != gcvNULL) + { + *ChipMinorFeatures2 = Hardware->chipMinorFeatures2; + } + + /* Success. */ + gcmkFOOTER_ARG("*ChipModel=0x%x *ChipRevision=0x%x *ChipFeatures=0x%08x " + "*ChipMinorFeatures=0x%08x *ChipMinorFeatures1=0x%08x " + "*ChipMinorFeatures2=0x%08x", + gcmOPT_VALUE(ChipModel), gcmOPT_VALUE(ChipRevision), + gcmOPT_VALUE(ChipFeatures), gcmOPT_VALUE(ChipMinorFeatures), + gcmOPT_VALUE(ChipMinorFeatures1), + gcmOPT_VALUE(ChipMinorFeatures2)); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_QueryChipSpecs( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR StreamCount, + OUT gctUINT32_PTR RegisterMax, + OUT gctUINT32_PTR ThreadCount, + OUT gctUINT32_PTR ShaderCoreCount, + OUT gctUINT32_PTR VertexCacheSize, + OUT gctUINT32_PTR VertexOutputBufferSize + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Return the number of streams. */ + if (StreamCount != gcvNULL) + { + *StreamCount = Hardware->streamCount; + } + + /* Return the number of temporary registers. */ + if (RegisterMax != gcvNULL) + { + *RegisterMax = Hardware->registerMax; + } + + /* Return the maximum number of thrteads. */ + if (ThreadCount != gcvNULL) + { + *ThreadCount = Hardware->threadCount; + } + + /* Return the number of shader cores. */ + if (ShaderCoreCount != gcvNULL) + { + *ShaderCoreCount = Hardware->shaderCoreCount; + } + + /* Return the number of entries in the vertex cache. */ + if (VertexCacheSize != gcvNULL) + { + *VertexCacheSize = Hardware->vertexCacheSize; + } + + /* Return the number of entries in the vertex output buffer. */ + if (VertexOutputBufferSize != gcvNULL) + { + *VertexOutputBufferSize = Hardware->vertexOutputBufferSize; + } + + /* Success. */ + gcmkFOOTER_ARG("*StreamCount=%u *RegisterMax=%u *ThreadCount=%u " + "*ShaderCoreCount=%u *VertexCacheSize=%u " + "*VertexOutputBufferSize=%u", + gcmOPT_VALUE(StreamCount), gcmOPT_VALUE(RegisterMax), + gcmOPT_VALUE(ThreadCount), gcmOPT_VALUE(ShaderCoreCount), + gcmOPT_VALUE(VertexCacheSize), + gcmOPT_VALUE(VertexOutputBufferSize)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertFormat +** +** Convert an API format to hardware parameters. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gceSURF_FORMAT Format +** API format to convert. +** +** OUTPUT: +** +** gctUINT32 * BitsPerPixel +** Pointer to a variable that will hold the number of bits per pixel. +** +** gctUINT32 * BytesPerTile +** Pointer to a variable that will hold the number of bytes per tile. +*/ +gceSTATUS +gckHARDWARE_ConvertFormat( + IN gckHARDWARE Hardware, + IN gceSURF_FORMAT Format, + OUT gctUINT32 * BitsPerPixel, + OUT gctUINT32 * BytesPerTile + ) +{ + gctUINT32 bitsPerPixel; + gctUINT32 bytesPerTile; + + gcmkHEADER_ARG("Hardware=0x%x Format=%d", Hardware, Format); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Dispatch on format. */ + switch (Format) + { + case gcvSURF_INDEX8: + case gcvSURF_A8: + case gcvSURF_L8: + /* 8-bpp format. */ + bitsPerPixel = 8; + bytesPerTile = (8 * 4 * 4) / 8; + break; + + case gcvSURF_YV12: + case gcvSURF_I420: + case gcvSURF_NV12: + case gcvSURF_NV21: + /* 12-bpp planar YUV formats. */ + bitsPerPixel = 12; + bytesPerTile = (12 * 4 * 4) / 8; + break; + + case gcvSURF_A8L8: + case gcvSURF_X4R4G4B4: + case gcvSURF_A4R4G4B4: + case gcvSURF_X1R5G5B5: + case gcvSURF_A1R5G5B5: + case gcvSURF_R5G5B5X1: + case gcvSURF_R4G4B4X4: + case gcvSURF_X4B4G4R4: + case gcvSURF_X1B5G5R5: + case gcvSURF_B4G4R4X4: + case gcvSURF_R5G6B5: + case gcvSURF_B5G5R5X1: + case gcvSURF_YUY2: + case gcvSURF_UYVY: + case gcvSURF_YVYU: + case gcvSURF_VYUY: + case gcvSURF_NV16: + case gcvSURF_NV61: + case gcvSURF_D16: + /* 16-bpp format. */ + bitsPerPixel = 16; + bytesPerTile = (16 * 4 * 4) / 8; + break; + + case gcvSURF_X8R8G8B8: + case gcvSURF_A8R8G8B8: + case gcvSURF_X8B8G8R8: + case gcvSURF_A8B8G8R8: + case gcvSURF_R8G8B8X8: + case gcvSURF_D32: + /* 32-bpp format. */ + bitsPerPixel = 32; + bytesPerTile = (32 * 4 * 4) / 8; + break; + + case gcvSURF_D24S8: + case gcvSURF_D24X8: + /* 24-bpp format. */ + bitsPerPixel = 32; + bytesPerTile = (32 * 4 * 4) / 8; + break; + + case gcvSURF_DXT1: + case gcvSURF_ETC1: + bitsPerPixel = 4; + bytesPerTile = (4 * 4 * 4) / 8; + break; + + case gcvSURF_DXT2: + case gcvSURF_DXT3: + case gcvSURF_DXT4: + case gcvSURF_DXT5: + bitsPerPixel = 8; + bytesPerTile = (8 * 4 * 4) / 8; + break; + + default: + /* Invalid format. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Set the result. */ + if (BitsPerPixel != gcvNULL) + { + * BitsPerPixel = bitsPerPixel; + } + + if (BytesPerTile != gcvNULL) + { + * BytesPerTile = bytesPerTile; + } + + /* Success. */ + gcmkFOOTER_ARG("*BitsPerPixel=%u *BytesPerTile=%u", + gcmOPT_VALUE(BitsPerPixel), gcmOPT_VALUE(BytesPerTile)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_SplitMemory +** +** Split a hardware specific memory address into a pool and offset. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctUINT32 Address +** Address in hardware specific format. +** +** OUTPUT: +** +** gcePOOL * Pool +** Pointer to a variable that will hold the pool type for the address. +** +** gctUINT32 * Offset +** Pointer to a variable that will hold the offset for the address. +*/ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Addres=%08x", Hardware, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + gcmkVERIFY_ARGUMENT(Offset != gcvNULL); + + /* Dispatch on memory type. */ + switch (( ((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) )) + { + case 0x0: + /* System memory. */ + *Pool = gcvPOOL_SYSTEM; + break; + + case 0x1: + /* Virtual memory. */ + *Pool = gcvPOOL_VIRTUAL; + break; + + default: + /* Invalid memory type. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Return offset of address. */ + *Offset = ( ((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) ); + + /* Success. */ + gcmkFOOTER_ARG("*Pool=%d *Offset=%08x", *Pool, *Offset); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Execute +** +** Kickstart the hardware's command processor with an initialized command +** buffer. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of command buffer. +** +** gctSIZE_T Bytes +** Number of bytes for the prefetch unit (until after the first LINK). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + gctUINT32 address = 0, control; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Bytes=%lu", + Hardware, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + +#ifdef __QNXNTO__ + if (PhysicalAddresses) + { + /* Convert physical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertPhysical(Hardware, Physical, &address)); + } + else + { +#endif + /* Convert logical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); +#ifdef __QNXNTO__ + } +#endif + + /* Enable all events. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00014, ~0U)); + + /* Write address register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00654, address)); + + /* Build control register. */ + control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes+7)>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + /* Set big endian */ + if (Hardware->bigEndian) + { + control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))); + } + + /* Write control register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00658, control)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Started command buffer @ %08x", + address); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_WaitLink +** +** Append a WAIT/LINK command sequence at the specified location in the command +** queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT/LINK command sequence at or gcvNULL just to query the size of the +** WAIT/LINK command sequence. +** +** gctUINT32 Offset +** Offset into command buffer required for alignment. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT/LINK command +** sequence. If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** by the WAIT/LINK command sequence. If 'Bytes' is gcvNULL, nothing will +** be returned. +** +** gctPOINTER * Wait +** Pointer to a variable that will receive the pointer to the WAIT +** command. If 'Wait' is gcvNULL nothing will be returned. +** +** gctSIZE_T * WaitSize +** Pointer to a variable that will receive the number of bytes used by +** the WAIT command. If 'LinkSize' is gcvNULL nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctPOINTER * Wait, + OUT gctSIZE_T * WaitSize + ) +{ + gceSTATUS status; + gctUINT32 address; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=%08x *Bytes=%lu", + Hardware, Logical, Offset, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Compute number of bytes required. */ + bytes = gcmALIGN(Offset + 16, 8) - Offset; + + if (Logical != gcvNULL) + { + /* Convert logical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, + Logical, + &address)); + + if (*Bytes < bytes) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append WAIT(200). */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (200) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: WAIT", address); + + /* Append LINK(2, address). */ + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[3] = address; + + Hardware->lastWaitLink = address; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: LINK %08x, #%lu", + address + 8, address, bytes); + + if (Wait != gcvNULL) + { + /* Return pointer to WAIT command. */ + *Wait = Logical; + } + + if (WaitSize != gcvNULL) + { + /* Return number of bytes used by the WAIT command. */ + *WaitSize = 8; + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT/LINK command + ** sequence. */ + *Bytes = bytes; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu *Wait=0x%x *WaitSize=%lu", + gcmOPT_VALUE(Bytes), gcmOPT_POINTER(Wait), + gcmOPT_VALUE(WaitSize)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_End +** +** Append an END command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** END command at or gcvNULL just to query the size of the END command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the END command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the END command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append END. */ + logical[0] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical); + + /* Make sure the CPU writes out the data to memory. */ + gcmkVERIFY_OK( + gckOS_MemoryBarrier(Hardware->os, Logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the END command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Nop +** +** Append a NOP command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** NOP command at or gcvNULL just to query the size of the NOP command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the NOP command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append NOP. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the NOP command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Wait +** +** Append a WAIT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT command at or gcvNULL just to query the size of the WAIT command. +** +** gctUINT32 Count +** Number of cycles to wait. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Count=%u *Bytes=%lu", + Hardware, Logical, Count, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append WAIT. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: WAIT %u", Logical, Count); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Event +** +** Append an EVENT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the EVENT command at or gcvNULL just to query the size of the EVENT +** command. +** +** gctUINT8 Event +** Event ID to program. +** +** gceKERNEL_WHERE FromWhere +** Location of the pipe to send the event. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the EVENT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the EVENT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT size; + gctUINT32 destination = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu", + Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + gcmkVERIFY_ARGUMENT(Event < 32); + + /* Determine the size of the command. */ + size = (Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL)) + ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */ + : 8; + + if (Logical != gcvNULL) + { + if (*Bytes < size) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + switch (FromWhere) + { + case gcvKERNEL_COMMAND: + /* From command processor. */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1&((gctUINT32)((((1?5:5)-(0?5:5)+1)==32)?~0:(~(~0<<((1?5:5)-(0?5:5)+1)))))))<<(0?5:5))); + break; + + case gcvKERNEL_PIXEL: + /* From pixel engine. */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1&((gctUINT32)((((1?6:6)-(0?6:6)+1)==32)?~0:(~(~0<<((1?6:6)-(0?6:6)+1)))))))<<(0?6:6))); + break; + + default: + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Append EVENT(Event, destiantion). */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); + + /* Make sure the event ID gets written out before GPU can access it. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + +#if gcdDEBUG + { + gctUINT32 phys; + gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: EVENT %d", phys, Event); + } +#endif + + /* Append the extra states. These are needed for the chips that do not + ** support back-to-back events due to the async interface. The extra + ** states add the necessary delay to ensure that event IDs do not + ** collide. */ + if (size > 8) + { + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + logical[3] = 0; + logical[4] = 0; + logical[5] = 0; + logical[6] = 0; + logical[7] = 0; + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the EVENT command. */ + *Bytes = size; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_PipeSelect +** +** Append a PIPESELECT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the PIPESELECT command at or gcvNULL just to query the size of the +** PIPESELECT command. +** +** gctUINT32 Pipe +** Pipe value to select. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the PIPESELECT command. +** If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the PIPESELECT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Pipe, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%u *Bytes=%lu", + Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Append a PipeSelect. */ + if (Logical != gcvNULL) + { + gctUINT32 flush, stall; + + if (*Bytes < 32) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + flush = (Pipe == 0x1) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))) + : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))); + + stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* LoadState(AQFlush, 1), flush. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH %x", logical, flush); + + /* LoadState(AQSempahore, 1), stall. */ + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[3] = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: SEMAPHORE %x", logical + 2, stall); + + /* Stall, stall. */ + logical[4] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + logical[5] = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: STALL %x", logical + 4, stall); + + /* LoadState(AQPipeSelect, 1), pipe. */ + logical[6] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[7] = Pipe; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: PIPE %u", logical + 6, Pipe); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the PIPESELECT command. */ + *Bytes = 32; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Link +** +** Append a LINK command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the LINK command at or gcvNULL just to query the size of the LINK +** command. +** +** gctPOINTER FetchAddress +** Logical address of destination of LINK. +** +** gctSIZE_T FetchSize +** Number of bytes in destination of LINK. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the LINK command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the LINK command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ) +{ + gceSTATUS status; + gctSIZE_T bytes; + gctUINT32 address; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu " + "*Bytes=%lu", + Hardware, Logical, FetchAddress, FetchSize, + gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Convert logical address to hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, FetchAddress, &address)); + + logical[1] = address; + + /* Make sure the address got written before the LINK command. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + + /* Compute number of 64-byte aligned bytes to fetch. */ + bytes = gcmALIGN(address + FetchSize, 64) - address; + + /* Append LINK(bytes / 8), FetchAddress. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes>>3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + +#if gcdDEBUG + { + gctUINT32 phys; + gckHARDWARE_ConvertLogical(Hardware, Logical, &phys); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: LINK %08x, #%lu", phys, address, bytes); + } +#endif + + /* Memory barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the LINK command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_AlignToTile +** +** Align the specified width and height to tile boundaries. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gceSURF_TYPE Type +** Type of alignment. +** +** gctUINT32 * Width +** Pointer to the width to be aligned. If 'Width' is gcvNULL, no width +** will be aligned. +** +** gctUINT32 * Height +** Pointer to the height to be aligned. If 'Height' is gcvNULL, no height +** will be aligned. +** +** OUTPUT: +** +** gctUINT32 * Width +** Pointer to a variable that will receive the aligned width. +** +** gctUINT32 * Height +** Pointer to a variable that will receive the aligned height. +** +** gctBOOL_PTR SuperTiled +** Pointer to a variable that receives the super-tiling flag for the +** surface. +*/ +gceSTATUS +gckHARDWARE_AlignToTile( + IN gckHARDWARE Hardware, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height, + OUT gctBOOL_PTR SuperTiled + ) +{ + gctBOOL superTiled = gcvFALSE; + gctUINT32 xAlignment, yAlignment; + + gcmkHEADER_ARG("Hardware=0x%x Type=%d *Width=%u *Height=%u", + Hardware, Type, gcmOPT_VALUE(Width), gcmOPT_VALUE(Height)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Super tiling can be enabled for render targets and depth buffers. */ + superTiled = + ( (Type == gcvSURF_RENDER_TARGET) + || (Type == gcvSURF_DEPTH) + ) + && + /* Of course, hardware needs to support super tiles. */ + ((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 12:12) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))); + + /* Compute alignment factors. */ + xAlignment = superTiled ? 64 + : (Type == gcvSURF_TEXTURE) ? 4 + : 16; + yAlignment = superTiled ? 64 : 4; + + if (Width != gcvNULL) + { + /* Align the width. */ + *Width = gcmALIGN(*Width, xAlignment); + } + + if (Height != gcvNULL) + { + /* Align the height. */ + *Height = gcmALIGN(*Height, yAlignment); + } + + if (SuperTiled != gcvNULL) + { + /* Copy the super tiling. */ + *SuperTiled = superTiled; + } + + /* Success. */ + gcmkFOOTER_ARG("*Width=%u *Height=%u *SuperTiled=%d", + gcmOPT_VALUE(Width), gcmOPT_VALUE(Height), + gcmOPT_VALUE(SuperTiled)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_UpdateQueueTail +** +** Update the tail of the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the start of the command queue. +** +** gctUINT32 Offset +** Offset into the command queue of the tail (last command). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=%08x", + Hardware, Logical, Offset); + + /* Verify the hardware. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Force a barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, Logical)); + + /* Notify gckKERNEL object of change. */ + gcmkONERROR( + gckKERNEL_Notify(Hardware->kernel, + gcvNOTIFY_COMMAND_QUEUE, + gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertLogical +** +** Convert a logical system address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Convert logical address into a physical address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Hardware->os, Logical, &address)); + + /* Return hardware specific address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertPhysical +** +** Convert a physical address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPHYS_ADDR Physical +** Physical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + address = (gctUINT32)Physical; + + /* Return hardware specific address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Return the status. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Interrupt +** +** Process an interrupt. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctBOOL InterruptValid +** If gcvTRUE, this function will read the interrupt acknowledge +** register, stores the data, and return whether or not the interrupt +** is ours or not. If gcvFALSE, this functions will read the interrupt +** acknowledge register and combine it with any stored value to handle +** the event notifications. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ) +{ + gckEVENT event; + gctUINT32 data; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x InterruptValid=%d", Hardware, InterruptValid); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Extract gckEVENT object. */ + event = Hardware->kernel->event; + gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); + + if (InterruptValid) + { + /* Read AQIntrAcknowledge register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00010, + &data)); + +#if gcdDEBUG + if (data & 0x80000000) + { + gcmkONERROR(gckOS_Broadcast(Hardware->os, + Hardware, + gcvBROADCAST_AXI_BUS_ERROR)); + } +#endif + + if (data == 0) + { + /* Not our interrupt. */ + status = gcvSTATUS_NOT_OUR_INTERRUPT; + } + else + { + /* Inform gckEVENT of the interrupt. */ + status = gckEVENT_Interrupt(event, data & 0x7FFFFFFF); + } + } + else + { + /* Handle events. */ + status = gckEVENT_Notify(event, 0); + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryCommandBuffer +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * Alignment +** Pointer to a variable receiving the alignment for each command. +** +** gctSIZE_T * ReservedHead +** Pointer to a variable receiving the number of reserved bytes at the +** head of each command buffer. +** +** gctSIZE_T * ReservedTail +** Pointer to a variable receiving the number of bytes reserved at the +** tail of each command buffer. +*/ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Alignment != gcvNULL) + { + /* Align every 8 bytes. */ + *Alignment = 8; + } + + if (ReservedHead != gcvNULL) + { + /* Reserve space for SelectPipe(). */ + *ReservedHead = 32; + } + + if (ReservedTail != gcvNULL) + { + /* Reserve space for Link(). */ + *ReservedTail = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu", + gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead), + gcmOPT_VALUE(ReservedTail)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QuerySystemMemory +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * SystemSize +** Pointer to a variable that receives the maximum size of the system +** memory. +** +** gctUINT32 * SystemBaseAddress +** Poinetr to a variable that receives the base address for system +** memory. +*/ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (SystemSize != gcvNULL) + { + /* Maximum system memory can be 2GB. */ + *SystemSize = 1U << 31; + } + + if (SystemBaseAddress != gcvNULL) + { + /* Set system memory base address. */ + *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))); + } + + /* Success. */ + gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu", + gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_SetMMU +** +** Set the page table base address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the page table. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ) +{ + gceSTATUS status; + gctUINT32 address = 0; + gctUINT32 baseAddress; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Convert the logical address into an hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); + + /* Also get the base address - we need a real physical address. */ + gcmkONERROR( + gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Setting page table to 0x%08X", + address + baseAddress); + + /* Write the AQMemoryFePageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00400, + address + baseAddress)); + + /* Write the AQMemoryRaPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00410, + address + baseAddress)); + + /* Write the AQMemoryTxPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00404, + address + baseAddress)); + + /* Write the AQMemoryPePageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00408, + address + baseAddress)); + + /* Write the AQMemoryPezPageTable register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x0040C, + address + baseAddress)); + + /* Return the status. */ + gcmkFOOTER_NO(); + return status; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_FlushMMU +** +** Flush the page table. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 flush; + gctUINT32_PTR buffer; + gctSIZE_T bufferSize; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Flush the memory controller. */ + flush = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1&((gctUINT32)((((1?2:2)-(0?2:2)+1)==32)?~0:(~(~0<<((1?2:2)-(0?2:2)+1)))))))<<(0?2:2))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1&((gctUINT32)((((1?4:4)-(0?4:4)+1)==32)?~0:(~(~0<<((1?4:4)-(0?4:4)+1)))))))<<(0?4:4))); + + gcmkONERROR( + gckCOMMAND_Reserve(Hardware->kernel->command, + 8, + (gctPOINTER *) &buffer, + &bufferSize)); + + buffer[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH MMU", buffer); + + gcmkONERROR( + gckCOMMAND_Execute(Hardware->kernel->command, 8)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_BuildVirtualAddress +** +** Build a virtual address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctUINT32 Index +** Index into page table. +** +** gctUINT32 Offset +** Offset into page. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable receiving te hardware address. +*/ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Build virtual address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (Offset|(Index<<12)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ) +{ + gceSTATUS status; + gctUINT32 idle = 0; + gctINT retry, poll, pollCount; + + gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + + /* If we have to wait, try 100 polls per millisecond. */ + pollCount = Wait ? 100 : 1; + + /* At most, try for 1 second. */ + for (retry = 0; retry < 1000; ++retry) + { + /* If we have to wait, try 100 polls per millisecond. */ + for (poll = pollCount; poll > 0; --poll) + { + /* Read register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00004, &idle)); + + /* See if we have to wait for FE idle. */ + if (( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* FE is idle. */ + break; + } + } + + /* Check if we need to wait for FE and FE is busy. */ + if (Wait && !( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Wait a little. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "%s: Waiting for idle: 0x%08X", + __FUNCTION__, idle); + + gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1)); + } + else + { + break; + } + } + + /* Return idle to caller. */ + *Data = idle; + + /* Success. */ + gcmkFOOTER_ARG("*Data=%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32 pipe; + gctUINT32 flush = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Flush=%x Logical=0x%x *Bytes=%lu", + Hardware, Flush, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get current pipe. */ + pipe = Hardware->kernel->command->pipeSelect; + + /* Flush 3D color cache. */ + if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1&((gctUINT32)((((1?1:1)-(0?1:1)+1)==32)?~0:(~(~0<<((1?1:1)-(0?1:1)+1)))))))<<(0?1:1))); + } + + /* Flush 3D depth cache. */ + if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1&((gctUINT32)((((1?0:0)-(0?0:0)+1)==32)?~0:(~(~0<<((1?0:0)-(0?0:0)+1)))))))<<(0?0:0))); + } + + /* Flush 3D texture cache. */ + if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1&((gctUINT32)((((1?2:2)-(0?2:2)+1)==32)?~0:(~(~0<<((1?2:2)-(0?2:2)+1)))))))<<(0?2:2))); + } + + /* Flush 2D cache. */ + if ((Flush & gcvFLUSH_2D) && (pipe == 0x1)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1&((gctUINT32)((((1?3:3)-(0?3:3)+1)==32)?~0:(~(~0<<((1?3:3)-(0?3:3)+1)))))))<<(0?3:3))); + } + + /* See if there is a valid flush. */ + if (flush == 0) + { + if (Bytes != gcvNULL) + { + /* No bytes required. */ + *Bytes = 0; + } + } + + else + { + /* Copy to command queue. */ + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append LOAD_STATE to AQFlush. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH %x", logical, flush); + } + + if (Bytes != gcvNULL) + { + /* 8 bytes required. */ + *Bytes = 8; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ) +{ + gctUINT32 debug; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d", + Hardware, Enable, Compression); + + /* Only process if fast clear is available. */ + if (( ((((gctUINT32) (Hardware->chipFeatures)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + if (Enable == -1) + { + /* Determine automatic value for fast clear. */ + Enable = (Hardware->chipModel != gcv500) + | (Hardware->chipRevision >= 3); + } + + if (Compression == -1) + { + /* Determine automatic value for compression. */ + Compression = Enable + & ( ((((gctUINT32) (Hardware->chipFeatures)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ); + } + + /* Read AQMemoryDebug register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, 0x00414, &debug)); + + /* Set fast clear bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable==0) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); + + /* Set copression bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) (Compression==0) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))); + + /* Write back AQMemoryDebug register. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00414, + debug)); + + /* Store fast clear and comprersison flags. */ + Hardware->allowFastClear = Enable; + Hardware->allowCompression = Compression; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "FastClear=%d Compression=%d", Enable, Compression); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +typedef enum +{ + gcvPOWER_FLAG_INITIALIZE = 1 << 0, + gcvPOWER_FLAG_STALL = 1 << 1, + gcvPOWER_FLAG_STOP = 1 << 2, + gcvPOWER_FLAG_START = 1 << 3, + gcvPOWER_FLAG_RELEASE = 1 << 4, + gcvPOWER_FLAG_DELAY = 1 << 5, + gcvPOWER_FLAG_SAVE = 1 << 6, + gcvPOWER_FLAG_ACQUIRE = 1 << 7, + gcvPOWER_FLAG_OFF = 1 << 8, + gcvPOWER_FLAG_CLOCK_OFF = 1 << 9, +} +gcePOWER_FLAGS; + +/******************************************************************************* +** +** gckHARDWARE_SetPowerManagementState +** +** Set GPU to a specified power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ) +{ +#if !gcdNO_POWER_MANAGEMENT + gceSTATUS status; + gckCOMMAND command = gcvNULL; + gckOS os; + gctUINT flag, clock; + gctPOINTER buffer; + gctSIZE_T bytes, requested; + gctBOOL acquired = gcvFALSE; + gctBOOL reserved = gcvFALSE; + gctBOOL mutexAcquired = gcvFALSE; + gctBOOL stall = gcvTRUE; + gctBOOL broadcast = gcvFALSE; + gctUINT32 process, thread; + + /* State transition flags. */ + static const gctUINT flags[4][4] = + { + /* gcvPOWER_ON */ + { /* ON */ 0, + /* OFF */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL, + /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_OFF */ + { /* ON */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY, + /* OFF */ 0, + /* IDLE */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY, + /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_IDLE */ + { /* ON */ gcvPOWER_FLAG_RELEASE, + /* OFF */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ 0, + /* SUSPEND */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_SUSPEND */ + { /* ON */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY, + /* OFF */ gcvPOWER_FLAG_SAVE | + gcvPOWER_FLAG_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY, + /* SUSPEND */ 0, + }, + }; + + /* Clocks. */ + static const gctUINT clocks[4] = + { + /* gcvPOWER_ON */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_OFF */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_IDLE */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_SUSPEND */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2)))| + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + }; + + gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get the gckOS object pointer. */ + os = Hardware->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Convert the broadcast power state. */ + switch (State) + { + case gcvPOWER_ON_BROADCAST: + /* Convert to ON and and not we are inside broadcast. */ + State = gcvPOWER_ON; + stall = gcvFALSE; + broadcast = gcvTRUE; + break; + + case gcvPOWER_SUSPEND_ATPOWERON: + /* Convert to SUSPEND and don't wait for STALL. */ + State = gcvPOWER_SUSPEND; + stall = gcvFALSE; + break; + + case gcvPOWER_OFF_ATPOWERON: + /* Convert to OFF and don't wait for STALL. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + break; + + case gcvPOWER_IDLE_BROADCAST: + /* Convert to IDLE and note we are inside broadcast. */ + State = gcvPOWER_IDLE; + broadcast = gcvTRUE; + break; + + case gcvPOWER_SUSPEND_BROADCAST: + /* Convert to SUSPEND and note we are inside broadcast. */ + State = gcvPOWER_SUSPEND; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_BROADCAST: + /* Convert to OFF and note we are inside broadcast. */ + State = gcvPOWER_OFF; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_RECOVERY: + /* Convert to OFF and note we are inside broadcast. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + broadcast = gcvTRUE; + break; + + default: + break; + } + + /* Get current process and thread IDs. */ + gcmkONERROR(gckOS_GetProcessID(&process)); + gcmkONERROR(gckOS_GetThreadID(&thread)); + + if (broadcast) + { + /* Try to acquire the power mutex. */ + status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0); + + if (status == gcvSTATUS_TIMEOUT) + { + /* Check if we already own this mutex. */ + if ((Hardware->powerProcess == process) + && (Hardware->powerThread == thread) + ) + { + /* Bail out on recursive power management. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); + } + } + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); + } + + Hardware->powerProcess = process; + Hardware->powerThread = thread; + mutexAcquired = gcvTRUE; + + /* Grab control flags and clock. */ + flag = flags[Hardware->chipPowerState][State]; + clock = clocks[State]; + + if ((flag == 0) || (Hardware->settingPowerState)) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* No need to do anything. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + if (broadcast && !Hardware->broadcast + && (Hardware->chipPowerState == gcvPOWER_OFF) + ) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* No broadcast while GPU is forced power off. */ + gcmkFOOTER_NO(); + return gcvSTATUS_CHIP_NOT_READY; + } + + Hardware->settingPowerState = gcvTRUE; + + gcmkASSERT(Hardware->kernel != gcvNULL); + gcmkASSERT(Hardware->kernel->command != gcvNULL); + command = Hardware->kernel->command; + + if (flag & gcvPOWER_FLAG_INITIALIZE) + { + /* Turn on the power. */ + gcmkONERROR(gckOS_SetGPUPower(Hardware->os, gcvTRUE, gcvTRUE)); + } + + if ((flag & gcvPOWER_FLAG_STALL) && stall) + { + gctBOOL idle; + gctINT32 atomValue; + + /* Check commit atom. */ + gcmkONERROR( + gckOS_AtomGet(Hardware->os, command->atomCommit, &atomValue)); + + if (atomValue > 0) + { + /* Commits are pending - abort power management. */ + status = broadcast ? gcvSTATUS_CHIP_NOT_READY + : gcvSTATUS_MORE_DATA; + goto OnError; + } + + if (broadcast) + { + /* Check for idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle)); + + if (!idle) + { + status = gcvSTATUS_CHIP_NOT_READY; + goto OnError; + } + } + + else + { + /* Get the size of the flush command. */ + gcmkONERROR(gckHARDWARE_Flush(Hardware, + gcvFLUSH_ALL, + gcvNULL, + &requested)); + + /* Reserve space in the command queue. */ + gcmkONERROR( + gckCOMMAND_Reserve(command, requested, &buffer, &bytes)); + + reserved = gcvTRUE; + + /* Append a flush. */ + gcmkONERROR(gckHARDWARE_Flush(Hardware, + gcvFLUSH_ALL, + buffer, + &bytes)); + + /* Execute the command queue. */ + acquired = gcvFALSE; + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + /* Wait to finish all commands. */ + gcmkONERROR(gckCOMMAND_Stall(command)); + } + } + + if (flag & gcvPOWER_FLAG_ACQUIRE) + { + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); + + acquired = gcvTRUE; + } + + if (flag & gcvPOWER_FLAG_STOP) + { + /* Stop the command parser. */ + gcmkONERROR(gckCOMMAND_Stop(command)); + + /* Stop the Isr. */ + gcmkONERROR(Hardware->stopIsr(Hardware->isrContext)); + } + + /* Write the clock control register. */ + gcmkONERROR(gckOS_WriteRegister(os, + 0x00000, + clock)); + + /* Done loading the frequency scaler. */ + gcmkONERROR(gckOS_WriteRegister(os, + 0x00000, + ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); + + if (flag & gcvPOWER_FLAG_DELAY) + { + /* Wait for the specified amount of time to settle coming back from + ** power-off or suspend state. */ + gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY)); + } + + if (flag & gcvPOWER_FLAG_INITIALIZE) + { + /* Initialize hardware. */ + gcmkONERROR( + gckHARDWARE_InitializeHardware(Hardware)); + + gcmkONERROR( + gckHARDWARE_SetFastClear(Hardware, + Hardware->allowFastClear, + Hardware->allowCompression)); + + /* Force the command queue to reload the next context. */ + command->currentContext = 0; + } + + if (flag & (gcvPOWER_FLAG_OFF | gcvPOWER_FLAG_CLOCK_OFF)) + { + /* Turn off the GPU power. */ + gcmkONERROR( + gckOS_SetGPUPower(os, + (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE + : gcvTRUE, + (flag & gcvPOWER_FLAG_OFF) ? gcvFALSE : gcvTRUE)); + } + + if (flag & gcvPOWER_FLAG_START) + { + /* Start the command processor. */ + gcmkONERROR(gckCOMMAND_Start(command)); + + /* Start the Isr. */ + gcmkONERROR(Hardware->startIsr(Hardware->isrContext)); + } + + if (flag & gcvPOWER_FLAG_RELEASE) + { + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore)); + } + + /* Save the new power state. */ + Hardware->chipPowerState = State; + Hardware->broadcast = broadcast; + Hardware->settingPowerState = gcvFALSE; + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (reserved) + { + /* Release command queue. */ + gcmkVERIFY_OK(gckCOMMAND_Release(command)); + } + + if (acquired) + { + /* Release semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Hardware->os, command->powerSemaphore)); + } + + if (mutexAcquired) + { + Hardware->settingPowerState = gcvFALSE; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + /* Do nothing */ + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckHARDWARE_QueryPowerManagementState +** +** Get GPU power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE* State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(State != gcvNULL); + + /* Return the statue. */ + *State = Hardware->chipPowerState; + + /* Success. */ + gcmkFOOTER_ARG("*State=%d", *State); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ) +{ + gceSTATUS status; + gctUINT32 idle, address; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL); + + /* We are idle when the power is not ON. */ + if (Hardware->chipPowerState != gcvPOWER_ON) + { + *IsIdle = gcvTRUE; + } + + else + { + /* Read idle register. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00004, &idle)); + + /* Pipe must be idle. */ + if ((( ((((gctUINT32) (idle)) >> (0 ? 1:1)) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 3:3)) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 4:4)) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 6:6)) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 7:7)) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1)))))) )!=1) + || (( ((((gctUINT32) (idle)) >> (0 ? 2:2)) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) )!=1) + ) + { + /* Something is busy. */ + *IsIdle = gcvFALSE; + } + + else + { + /* Read the current FE address. */ + gcmkONERROR(gckOS_ReadRegister(Hardware->os, + 0x00664, + &address)); + + /* Test if address is inside the last WAIT/LINK sequence. */ + if ((address >= Hardware->lastWaitLink) + && (address <= Hardware->lastWaitLink + 16) + ) + { + /* FE is in last WAIT/LINK and the pipe is idle. */ + *IsIdle = gcvTRUE; + } + else + { + /* FE is not in WAIT/LINK yet. */ + *IsIdle = gcvFALSE; + } + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** Handy macros that will help in reading those debug registers. +*/ + +#define gcmkREAD_DEBUG_REGISTER(control, block, index, data) \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + index))); \ + gcmkONERROR( \ + gckOS_ReadRegister(Hardware->os, \ + GC_DEBUG_SIGNALS_##block##_Address, \ + &profiler->data)) + +#define gcmkRESET_DEBUG_REGISTER(control, block) \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 15))); \ + gcmkONERROR( \ + gckOS_WriteRegister(Hardware->os, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 0))) + +/******************************************************************************* +** +** gckHARDWARE_ProfileEngine2D +** +** Read the profile registers available in the 2D engine and sets them in the +** profile. The function will also reset the pixelsRendered counter every time. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** OPTIONAL gcs2D_PROFILE_PTR Profile +** Pointer to a gcs2D_Profile structure. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OPTIONAL gcs2D_PROFILE_PTR Profile + ) +{ + gceSTATUS status; + gcs2D_PROFILE_PTR profiler = Profile; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Profile != gcvNULL) + { + /* Read the cycle count. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00438, + &Profile->cycleCount)); + + /* Read pixels rendered by 2D engine. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pixelsRendered)); + + /* Reset counter. */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ) +{ + gceSTATUS status; + gcsPROFILER_COUNTERS * profiler = Counters; + + gcmkHEADER_ARG("Hardware=0x%x Counters=0x%x", Hardware, Counters); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the counters. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00040, + &profiler->gpuTotalRead64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00044, + &profiler->gpuTotalWrite64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00438, + &profiler->gpuCyclesCounter)); + + /* Reset counters. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x0003C, 1)); + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x0003C, 0)); + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, 0x00438, 0)); + + /* PE */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_killed_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_killed_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_drawn_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00454, &profiler->pe_pixel_count_drawn_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + + /* SH */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->ps_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->rendered_pixel_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vs_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->rendered_vertice_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vtx_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->vtx_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->pxl_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0045C, &profiler->pxl_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00470, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +))); + + /* PA */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_input_vtx_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_input_prim_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_output_prim_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_depth_clipped_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_trivial_rejected_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00460, &profiler->pa_culled_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +))); + + /* SE */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00464, &profiler->se_culled_triangle_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00464, &profiler->se_culled_lines_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +))); + + /* RA */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_valid_pixel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_total_quad_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_valid_quad_count_after_early_z)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_total_primitive_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_pipe_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00448, &profiler->ra_prefetch_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +))); + + /* TX */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_bilinear_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_trilinear_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_discarded_texture_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_total_texture_requests)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_mem_read_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_mem_read_in_8B_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_miss_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_hit_texel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0044C, &profiler->tx_cache_miss_texel_count)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00474, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +))); + + /* MC */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_read_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_read_req_8B_from_IP)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x00468, &profiler->mc_total_write_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +))); + + /* HI */ + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_read_request_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_write_request_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_ReadRegister(Hardware->os, 0x0046C, &profiler->hi_axi_cycles_write_data_stalled)); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) ))); + gcmkONERROR(gckOS_WriteRegister(Hardware->os, 0x00478, ( ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +))); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 control, idle; + gckCOMMAND command; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkASSERT(Hardware->kernel != gcvNULL); + command = Hardware->kernel->command; + gcmkASSERT(command != gcvNULL); + + if (Hardware->chipRevision < 0x4600) + { + /* Not supported - we need the isolation bit. */ + gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); + } + + if (Hardware->chipPowerState == gcvPOWER_ON) + { + /* Acquire the power management semaphore. */ + gcmkONERROR( + gckOS_AcquireSemaphore(Hardware->os, command->powerSemaphore)); + acquired = gcvTRUE; + } + + if ((Hardware->chipPowerState == gcvPOWER_ON) + || (Hardware->chipPowerState == gcvPOWER_IDLE) + ) + { + /* Stop the command processor. */ + gcmkONERROR( + gckCOMMAND_Stop(command)); + + /* Grab the queue mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Hardware->os, + command->mutexQueue, + gcvINFINITE)); + } + + /* Read register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00000, + &control)); + + for (;;) + { + /* Isolate the GPU. */ + control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + control)); + + /* Set soft reset. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Wait for reset. */ + gcmkONERROR( + gckOS_Delay(Hardware->os, 1)); + + /* Reset soft reset bit. */ + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Reset GPU isolation. */ + control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR( + gckOS_WriteRegister(Hardware->os, + 0x00000, + control)); + + /* Read idle register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00004, + &idle)); + + if (( ((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )==0) + { + continue; + } + + /* Read reset register. */ + gcmkONERROR( + gckOS_ReadRegister(Hardware->os, + 0x00000, + &control)); + + if ((( ((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) )==0) + || (( ((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) )==0) + ) + { + continue; + } + + /* GPU is idle. */ + break; + } + + /* Force an OFF to ON power switch. */ + Hardware->chipPowerState = gcvPOWER_OFF; + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Hardware->os, command->powerSemaphore)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Test if we have a new Memory Controller. */ + if (((((gctUINT32) (Hardware->chipMinorFeatures0)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))))) + { + /* No base address required. */ + *BaseAddress = 0; + } + else + { + /* Get the base address from the OS. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, BaseAddress)); + } + + /* Success. */ + gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ) +{ + gctBOOL need = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL); + + /* Make sure this is a load state. */ + if (((((gctUINT32) (State)) >> (0 ? 31:27) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27)+1)))))))) + { + /* Get the state address. */ + switch (( ((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0)+1)))))))) + { + case 0x0596: + case 0x0597: + case 0x0599: + case 0x059A: + case 0x05A9: + /* These states need a TRUE physical address. */ + need = gcvTRUE; + break; + } + } + + /* Return the flag. */ + *NeedBase = need; + + /* Success. */ + gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_SetIsrManager( + IN gckHARDWARE Hardware, + IN gctISRMANAGERFUNC StartIsr, + IN gctISRMANAGERFUNC StopIsr, + IN gctPOINTER Context + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Hardware=0x%x, StartIsr=0x%x, StopIsr=0x%x, Context=0x%x", + Hardware, StartIsr, StopIsr, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (StartIsr == gcvNULL || + StopIsr == gcvNULL || + Context == gcvNULL) + { + status = gcvSTATUS_INVALID_ARGUMENT; + + gcmkFOOTER(); + return status; + } + + Hardware->startIsr = StartIsr; + Hardware->stopIsr = StopIsr; + Hardware->isrContext = Context; + + /* Success. */ + gcmkFOOTER(); + + return status; +} + diff --git a/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h b/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h new file mode 100644 index 0000000..67b7d53 --- /dev/null +++ b/kernel_drivers/v2/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h @@ -0,0 +1,97 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_hardware_h_ +#define __gc_hal_kernel_hardware_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* gckHARDWARE object. */ +struct _gckHARDWARE +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gctKERNEL object. */ + gckKERNEL kernel; + + /* Pointer to gctOS object. */ + gckOS os; + + /* Chip characteristics. */ + gceCHIPMODEL chipModel; + gctUINT32 chipRevision; + gctUINT32 chipFeatures; + gctUINT32 chipMinorFeatures0; + gctUINT32 chipMinorFeatures1; + gctUINT32 chipMinorFeatures2; + gctBOOL allowFastClear; + gctBOOL allowCompression; + gctUINT32 powerBaseAddress; + gctBOOL extraEventStates; + + gctUINT32 streamCount; + gctUINT32 registerMax; + gctUINT32 threadCount; + gctUINT32 shaderCoreCount; + gctUINT32 vertexCacheSize; + gctUINT32 vertexOutputBufferSize; + + /* Big endian */ + gctBOOL bigEndian; + + /* Chip status */ + gctPOINTER powerMutex; + gctUINT32 powerProcess; + gctUINT32 powerThread; + gceCHIPPOWERSTATE chipPowerState; + gctBOOL broadcast; + gctBOOL settingPowerState; + gctUINT32 lastWaitLink; + + gctISRMANAGERFUNC startIsr; + gctISRMANAGERFUNC stopIsr; + gctPOINTER isrContext; +}; + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ); + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_hardware_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal.h b/kernel_drivers/v2/hal/inc/gc_hal.h new file mode 100644 index 0000000..1829e7d --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal.h @@ -0,0 +1,1900 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_h_ +#define __gc_hal_h_ + +#include "gc_hal_types.h" +#include "gc_hal_enum.h" +#include "gc_hal_base.h" +#include "gc_hal_profiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* Alignment Macros ******************************* +\******************************************************************************/ + +#define gcmALIGN(n, align) \ +( \ + ((n) + ((align) - 1)) & ~((align) - 1) \ +) + +/******************************************************************************\ +***************************** Element Count Macro ***************************** +\******************************************************************************/ + +#define gcmSIZEOF(a) \ +( \ + (gctSIZE_T) (sizeof(a)) \ +) + +#define gcmCOUNTOF(a) \ +( \ + sizeof(a) / sizeof(a[0]) \ +) + +/******************************************************************************\ +******************************** gcsOBJECT Object ******************************* +\******************************************************************************/ + +/* Type of objects. */ +typedef enum _gceOBJECT_TYPE +{ + gcvOBJ_UNKNOWN = 0, + gcvOBJ_2D = gcmCC('2','D',' ',' '), + gcvOBJ_3D = gcmCC('3','D',' ',' '), + gcvOBJ_ATTRIBUTE = gcmCC('A','T','T','R'), + gcvOBJ_BRUSHCACHE = gcmCC('B','R','U','$'), + gcvOBJ_BRUSHNODE = gcmCC('B','R','U','n'), + gcvOBJ_BRUSH = gcmCC('B','R','U','o'), + gcvOBJ_BUFFER = gcmCC('B','U','F','R'), + gcvOBJ_COMMAND = gcmCC('C','M','D',' '), + gcvOBJ_COMMANDBUFFER = gcmCC('C','M','D','B'), + gcvOBJ_CONTEXT = gcmCC('C','T','X','T'), + gcvOBJ_DEVICE = gcmCC('D','E','V',' '), + gcvOBJ_DUMP = gcmCC('D','U','M','P'), + gcvOBJ_EVENT = gcmCC('E','V','N','T'), + gcvOBJ_FUNCTION = gcmCC('F','U','N','C'), + gcvOBJ_HAL = gcmCC('H','A','L',' '), + gcvOBJ_HARDWARE = gcmCC('H','A','R','D'), + gcvOBJ_HEAP = gcmCC('H','E','A','P'), + gcvOBJ_INDEX = gcmCC('I','N','D','X'), + gcvOBJ_INTERRUPT = gcmCC('I','N','T','R'), + gcvOBJ_KERNEL = gcmCC('K','E','R','N'), + gcvOBJ_MEMORYBUFFER = gcmCC('M','E','M','B'), + gcvOBJ_MMU = gcmCC('M','M','U',' '), + gcvOBJ_OS = gcmCC('O','S',' ',' '), + gcvOBJ_OUTPUT = gcmCC('O','U','T','P'), + gcvOBJ_PAINT = gcmCC('P','N','T',' '), + gcvOBJ_PATH = gcmCC('P','A','T','H'), + gcvOBJ_QUEUE = gcmCC('Q','U','E',' '), + gcvOBJ_SAMPLER = gcmCC('S','A','M','P'), + gcvOBJ_SHADER = gcmCC('S','H','D','R'), + gcvOBJ_STREAM = gcmCC('S','T','R','M'), + gcvOBJ_SURF = gcmCC('S','U','R','F'), + gcvOBJ_TEXTURE = gcmCC('T','X','T','R'), + gcvOBJ_UNIFORM = gcmCC('U','N','I','F'), + gcvOBJ_VARIABLE = gcmCC('V','A','R','I'), + gcvOBJ_VERTEX = gcmCC('V','R','T','X'), + gcvOBJ_VIDMEM = gcmCC('V','M','E','M'), + gcvOBJ_VG = gcmCC('V','G',' ',' '), +} +gceOBJECT_TYPE; + +/* gcsOBJECT object defintinon. */ +typedef struct _gcsOBJECT +{ + /* Type of an object. */ + gceOBJECT_TYPE type; +} +gcsOBJECT; + +/* Kernel settings. */ +typedef struct _gcsKERNEL_SETTINGS +{ + /* Used RealTime signal between kernel and user. */ + gctINT signal; +} +gcsKERNEL_SETTINGS; + +typedef struct _gckHARDWARE * gckHARDWARE; + +/******************************************************************************* +** +** gcmVERIFY_OBJECT +** +** Assert if an object is invalid or is not of the specified type. If the +** object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT +** will be returned from the current function. In retail mode this macro +** does nothing. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_OBJECT(prefix, obj, t) \ + do \ + { \ + if ((obj) == gcvNULL) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: NULL"); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT((obj) != gcvNULL); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } \ + else if (((gcsOBJECT*) (obj))->type != t) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: %c%c%c%c", \ + gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcm, obj, t) +# define gcmkVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcmk, obj, t) +#else +# define gcmVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +# define gcmkVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +#endif + +/******************************************************************************\ +********************************** gckOS Object ********************************* +\******************************************************************************/ + +typedef struct _gckOS * gckOS; + +/* Construct a new gckOS object. */ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ); + +/* Destroy an gckOS object. */ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ); + +/* Query the video memory. */ +gceSTATUS +gckOS_QueryVideoMemory( + IN gckOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free allocated memory. */ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Wrapper for allocation memory.. */ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Wrapper for freeing memory. */ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocateVirtualMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Wrapper for freeing virtual memory. */ +gceSTATUS +gckOS_FreeVirtualMemory( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Lock pages. */ +gceSTATUS +gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, +#endif + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ); + +/* Map pages. */ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctPOINTER Logical, +#endif + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ); + +/* Unlock pages. */ +gceSTATUS +gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, +#endif + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Free paged memory. */ +gceSTATUS +gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ); + +/* Allocate non-paged memory. */ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non-paged memory. */ +gceSTATUS +gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Get the number fo bytes per page. */ +gceSTATUS +gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ); + +/* Get the physical address of a corresponding logical address. */ +gceSTATUS +gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +/* Map physical memory. */ +gceSTATUS +gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap previously mapped physical memory. */ +gceSTATUS +gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Read data from a hardware register. */ +gceSTATUS +gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +/* Write data to a hardware register. */ +gceSTATUS +gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Write data to a 32-bit memory location. */ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ); + +/* Map physical memory into the process space. */ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap physical memory from the process space. */ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Create a new mutex. */ +gceSTATUS +gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Atomically exchange a pair of 32-bit values. */ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ); + +/* Atomically exchange a pair of pointers. */ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ); + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ); + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ); + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ); + +/* Memory barrier. */ +gceSTATUS +gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ); + +/* Map user pointer. */ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ); + +/* Unmap user pointer. */ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ); + +#ifdef __QNXNTO__ +/* Map user physical address. */ +gceSTATUS +gckOS_MapUserPhysical( + IN gckOS Os, + IN gctPHYS_ADDR Phys, + OUT gctPOINTER * KernelPointer + ); + +/* Allocate from user's shared pool. */ +gceSTATUS +gckOS_AllocateNonPagedMemoryShmPool( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN gctUINT32 Pid, + IN gctHANDLE Handle, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); +#endif + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ); + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Perform a memory copy. */ +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Device I/O control to the kernel HAL layer. */ +gceSTATUS +gckOS_DeviceControl( + IN gckOS Os, + IN gctBOOL FromUser, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + OUT gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ); + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ); + +/******************************************************************************\ +********************************** Signal Object ********************************* +\******************************************************************************/ + +/* User signal command codes. */ +typedef enum _gceUSER_SIGNAL_COMMAND_CODES +{ + gcvUSER_SIGNAL_CREATE, + gcvUSER_SIGNAL_DESTROY, + gcvUSER_SIGNAL_SIGNAL, + gcvUSER_SIGNAL_WAIT, +} +gceUSER_SIGNAL_COMMAND_CODES; + +/* Create a signal. */ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Wait for a signal uninterruptibly. */ +gceSTATUS +gckOS_WaitSignalUninterruptible( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Map a user signal to the kernel space. */ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ); + +/* Unmap a user signal */ +gceSTATUS +gckOS_UnmapSignal( + IN gckOS Os, + IN gctSIGNAL MappedSignal + ); + +/* Map user memory. */ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +#if !USE_NEW_LINUX_SIGNAL +/* Create signal to be used in the user space. */ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ); + +/* Destroy signal used in the user space. */ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ); + +/* Wait for signal used in the user space. */ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ); + +/* Signal a signal used in the user space. */ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ); +#endif /* USE_NEW_LINUX_SIGNAL */ + +/* Set a signal owned by a process. */ +#if defined(__QNXNTO__) +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctINT Recvid, + IN gctINT Coid + ); +#else +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ); +#endif + +/******************************************************************************\ +** Cache Support +*/ + +gceSTATUS +gckOS_CacheFlush( + gckOS Os, + gctHANDLE ProcessId, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +gceSTATUS +gckOS_CacheInvalidate( + gckOS Os, + gctHANDLE ProcessId, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +/******************************************************************************\ +** Debug Support +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gckOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +/******************************************************************************* +** Broadcast interface. +*/ + +typedef enum _gceBROADCAST +{ + /* GPU might be idle. */ + gcvBROADCAST_GPU_IDLE, + + /* A commit is going to happen. */ + gcvBROADCAST_GPU_COMMIT, + + /* GPU seems to be stuck. */ + gcvBROADCAST_GPU_STUCK, + + /* First process gets attached. */ + gcvBROADCAST_FIRST_PROCESS, + + /* Last process gets detached. */ + gcvBROADCAST_LAST_PROCESS, + + /* AXI bus error. */ + gcvBROADCAST_AXI_BUS_ERROR, +} +gceBROADCAST; + +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ); + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object.ß +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ); + +/******************************************************************************* +** Semaphores. +*/ + +/* Create a new semaphore. */ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ); + +/* Delete a semahore. */ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Acquire a semahore. */ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Release a semahore. */ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/******************************************************************************\ +********************************* gckHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gckHEAP * gckHEAP; + +/* Construct a new gckHEAP object. */ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ); + +/* Destroy an gckHEAP object. */ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +/* Free memory. */ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Node + ); + +/* Profile the heap. */ +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ); + +gceSTATUS +gckHEAP_ProfileEnd( + IN gckHEAP Heap, + IN gctCONST_STRING Title + ); + +#if defined gcdHAL_TEST +gceSTATUS +gckHEAP_Test( + IN gckHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ); +#endif + +/******************************************************************************\ +******************************** gckVIDMEM Object ****************************** +\******************************************************************************/ + +typedef struct _gckVIDMEM * gckVIDMEM; +typedef union _gcuVIDMEM_NODE * gcuVIDMEM_NODE_PTR; +typedef struct _gckKERNEL * gckKERNEL; + +/* Construct a new gckVIDMEM object. */ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T Banking, + OUT gckVIDMEM * Memory + ); + +/* Destroy an gckVDIMEM object. */ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ); + +/* Allocate rectangular memory. */ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Allocate linear memory. */ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Free memory. */ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ); + +/* Lock memory. */ +gceSTATUS +gckVIDMEM_Lock( + IN gcuVIDMEM_NODE_PTR Node, + OUT gctUINT32 * Address + ); + +/* Unlock memory. */ +gceSTATUS +gckVIDMEM_Unlock( + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ); + +/* Construct a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Destroy a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ); + +#ifdef __QNXNTO__ +/* Set the allocating process' PID for this node. */ +gceSTATUS +gckVIDMEM_SetPID( + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT32 Pid); +#endif + +/******************************************************************************\ +******************************** gckKERNEL Object ****************************** +\******************************************************************************/ + +struct _gcsHAL_INTERFACE; + +/* Notifications. */ +typedef enum _gceNOTIFY +{ + gcvNOTIFY_INTERRUPT, + gcvNOTIFY_COMMAND_QUEUE, +} +gceNOTIFY; + +/* Event locations. */ +typedef enum _gceKERNEL_WHERE +{ + gcvKERNEL_COMMAND, + gcvKERNEL_VERTEX, + gcvKERNEL_TRIANGLE, + gcvKERNEL_TEXTURE, + gcvKERNEL_PIXEL, +} +gceKERNEL_WHERE; + +/* Flush flags. */ +typedef enum _gceKERNEL_FLUSH +{ + gcvFLUSH_COLOR = 0x01, + gcvFLUSH_DEPTH = 0x02, + gcvFLUSH_TEXTURE = 0x04, + gcvFLUSH_2D = 0x08, + gcvFLUSH_ALL = gcvFLUSH_COLOR + | gcvFLUSH_DEPTH + | gcvFLUSH_TEXTURE + | gcvFLUSH_2D, +} +gceKERNEL_FLUSH; + +/* Construct a new gckKERNEL object. */ +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + OUT gckKERNEL * Kernel + ); + +/* Destroy an gckKERNEL object. */ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ); + +/* Dispatch a user-level command. */ +gceSTATUS +gckKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Query the video memory. */ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Lookup the gckVIDMEM object for a pool. */ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ); + +/* Map video memory. */ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, + IN gctUINT32 Bytes, +#endif + OUT gctPOINTER * Logical + ); + +#ifdef __QNXNTO__ +/* Unmap video memory. */ +gceSTATUS +gckKERNEL_UnmapVideoMemory( + IN gckKERNEL Kernel, + IN gctPOINTER Logical, + IN gctUINT32 Pid, + IN gctUINT32 Bytes + ); +#endif + +/* Map memory. */ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap memory. */ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Notification of events. */ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notifcation, + IN gctBOOL Data + ); + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ); + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ); + +/******************************************************************************\ +******************************* gckHARDWARE Object ***************************** +\******************************************************************************/ + +/* Construct a new gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + OUT gckHARDWARE * Hardware + ); + +/* Destroy an gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ); + +/* Query system memory requirements. */ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ); + +/* Build virtual address. */ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ); + +/* Query command buffer requirements. */ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ); + +/* Add a WAIT/LINK pair in the command queue. */ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctPOINTER * Wait, + OUT gctSIZE_T * WaitBytes + ); + +/* Kickstart the command processor. */ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ); + +/* Add an END command in the command queue. */ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a NOP command in the command queue. */ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a WAIT command in the command queue. */ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a PIPESELECT command in the command queue. */ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Pipe, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a LINK command in the command queue. */ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ); + +/* Add an EVENT command in the command queue. */ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ); + +/* Query the available memory. */ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures, + OUT gctUINT32* ChipMinorFeatures1, + OUT gctUINT32* ChipMinorFeatures2 + ); + +/* Query the specifications sof the hardware. */ +gceSTATUS +gckHARDWARE_QueryChipSpecs( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR StreamCount, + OUT gctUINT32_PTR RegisterMax, + OUT gctUINT32_PTR ThreadCount, + OUT gctUINT32_PTR ShaderCoreCount, + OUT gctUINT32_PTR VertexCacheSize, + OUT gctUINT32_PTR VertexOutputBufferSize + ); + +/* Convert an API format. */ +gceSTATUS +gckHARDWARE_ConvertFormat( + IN gckHARDWARE Hardware, + IN gceSURF_FORMAT Format, + OUT gctUINT32 * BitsPerPixel, + OUT gctUINT32 * BytesPerTile + ); + +/* Split a harwdare specific address into API stuff. */ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ); + +/* Align size to tile boundary. */ +gceSTATUS +gckHARDWARE_AlignToTile( + IN gckHARDWARE Hardware, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height, + OUT gctBOOL_PTR SuperTiled + ); + +/* Update command queue tail pointer. */ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ); + +/* Convert logical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +#ifdef __QNXNTO__ +/* Convert physical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ); +#endif + +/* Interrupt manager. */ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ); + +/* Program MMU. */ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ); + +/* Flush the MMU. */ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ); + +/* Get idle register. */ +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ); + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Enable/disable fast clear. */ +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ); + +gceSTATUS +gckHARDWARE_ReadInterrupt( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR IDs + ); + +/* Power management. */ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ); + +/* Profile 2D Engine. */ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OUT gcs2D_PROFILE_PTR Profile + ); + +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ); + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ); + +typedef gceSTATUS (*gctISRMANAGERFUNC)(gctPOINTER Context); + +gceSTATUS +gckHARDWARE_SetIsrManager( + IN gckHARDWARE Hardware, + IN gctISRMANAGERFUNC StartIsr, + IN gctISRMANAGERFUNC StopIsr, + IN gctPOINTER Context + ); + +/******************************************************************************\ +***************************** gckINTERRUPT Object ****************************** +\******************************************************************************/ + +typedef struct _gckINTERRUPT * gckINTERRUPT; + +typedef gceSTATUS (* gctINTERRUPT_HANDLER)( + IN gckKERNEL Kernel + ); + +gceSTATUS +gckINTERRUPT_Construct( + IN gckKERNEL Kernel, + OUT gckINTERRUPT * Interrupt + ); + +gceSTATUS +gckINTERRUPT_Destroy( + IN gckINTERRUPT Interrupt + ); + +gceSTATUS +gckINTERRUPT_SetHandler( + IN gckINTERRUPT Interrupt, + IN OUT gctINT32_PTR Id, + IN gctINTERRUPT_HANDLER Handler + ); + +gceSTATUS +gckINTERRUPT_Notify( + IN gckINTERRUPT Interrupt, + IN gctBOOL Valid + ); + +/******************************************************************************\ +******************************** gckEVENT Object ******************************* +\******************************************************************************/ + +typedef struct _gckEVENT * gckEVENT; + +/* Construct a new gckEVENT object. */ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ); + +/* Destroy an gckEVENT object. */ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ); + +/* Schedule a FreeNonPagedMemory event. */ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeContiguousMemory event. */ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeVideoMemory event. */ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a signal event. */ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule an Unlock event. */ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ); + +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait + ); + +struct _gcsQUEUE; + +/* Commit an event queue. */ +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN struct _gcsQUEUE * Queue + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +/******************************************************************************\ +******************************* gckCOMMAND Object ****************************** +\******************************************************************************/ + +typedef struct _gckCOMMAND * gckCOMMAND; + +/* Construct a new gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ); + +/* Destroy an gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ); + +/* Start the command queue. */ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ); + +/* Stop the command queue. */ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command + ); + +/* Commit a buffer to the command queue. */ +gceSTATUS +gckCOMMAND_Commit( + IN gckCOMMAND Command, + IN gcoCMDBUF CommandBuffer, + IN gcoCONTEXT Context, + IN gctHANDLE Process + ); + +/* Reserve space in the command buffer. */ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ); + +/* Release reserved space in the command buffer. */ +gceSTATUS +gckCOMMAND_Release( + IN gckCOMMAND Command + ); + +/* Execute reserved space in the command buffer. */ +gceSTATUS +gckCOMMAND_Execute( + IN gckCOMMAND Command, + IN gctSIZE_T RequstedBytes + ); + +/* Stall the command queue. */ +gceSTATUS +gckCOMMAND_Stall( + IN gckCOMMAND Command + ); + +/******************************************************************************\ +********************************* gckMMU Object ******************************** +\******************************************************************************/ + +typedef struct _gckMMU * gckMMU; + +/* Construct a new gckMMU object. */ +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ); + +/* Destroy an gckMMU object. */ +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ); + +/* Allocate pages inside the MMU. */ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ); + +/* Remove a page table from the MMU. */ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ); + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); +#endif + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckMMU Mmu, + IN gctHANDLE Handle + ); +#endif + +#if defined gcdHAL_TEST +gceSTATUS +gckMMU_Test( + IN gckMMU Mmu, + IN gctSIZE_T Vectors, + IN gctINT MaxSize + ); +#endif + +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_base.h b/kernel_drivers/v2/hal/inc/gc_hal_base.h new file mode 100644 index 0000000..d224b11 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_base.h @@ -0,0 +1,2573 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_base_h_ +#define __gc_hal_base_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" +#include "gc_hal_dump.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoHAL * gcoHAL; +typedef struct _gcoOS * gcoOS; +typedef struct _gco2D * gco2D; +typedef struct _gcoVG * gcoVG; +typedef struct _gco3D * gco3D; +typedef struct _gcoSURF * gcoSURF; +typedef struct _gcsSURF_INFO * gcsSURF_INFO_PTR; +typedef struct _gcsSURF_NODE * gcsSURF_NODE_PTR; +typedef struct _gcsSURF_FORMAT_INFO * gcsSURF_FORMAT_INFO_PTR; +typedef struct _gcsPOINT * gcsPOINT_PTR; +typedef struct _gcsSIZE * gcsSIZE_PTR; +typedef struct _gcsRECT * gcsRECT_PTR; +typedef struct _gcsBOUNDARY * gcsBOUNDARY_PTR; +typedef struct _gcoDUMP * gcoDUMP; +typedef struct _gcoHARDWARE * gcoHARDWARE; + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +/* Video memory pool type. */ +typedef enum _gcePOOL +{ + gcvPOOL_UNKNOWN, + gcvPOOL_DEFAULT, + gcvPOOL_LOCAL, + gcvPOOL_LOCAL_INTERNAL, + gcvPOOL_LOCAL_EXTERNAL, + gcvPOOL_UNIFIED, + gcvPOOL_SYSTEM, + gcvPOOL_VIRTUAL, + gcvPOOL_USER, + gcvPOOL_CONTIGUOUS +} +gcePOOL; + +/* Blending functions. */ +typedef enum _gceBLEND_FUNCTION +{ + gcvBLEND_ZERO, + gcvBLEND_ONE, + gcvBLEND_SOURCE_COLOR, + gcvBLEND_INV_SOURCE_COLOR, + gcvBLEND_SOURCE_ALPHA, + gcvBLEND_INV_SOURCE_ALPHA, + gcvBLEND_TARGET_COLOR, + gcvBLEND_INV_TARGET_COLOR, + gcvBLEND_TARGET_ALPHA, + gcvBLEND_INV_TARGET_ALPHA, + gcvBLEND_SOURCE_ALPHA_SATURATE, + gcvBLEND_CONST_COLOR, + gcvBLEND_INV_CONST_COLOR, + gcvBLEND_CONST_ALPHA, + gcvBLEND_INV_CONST_ALPHA, +} +gceBLEND_FUNCTION; + +/* Blending modes. */ +typedef enum _gceBLEND_MODE +{ + gcvBLEND_ADD, + gcvBLEND_SUBTRACT, + gcvBLEND_REVERSE_SUBTRACT, + gcvBLEND_MIN, + gcvBLEND_MAX, +} +gceBLEND_MODE; + +/* API flags. */ +typedef enum _gceAPI +{ + gcvAPI_D3D = 0x1, + gcvAPI_OPENGL = 0x2, +} +gceAPI; + +/* Depth modes. */ +typedef enum _gceDEPTH_MODE +{ + gcvDEPTH_NONE, + gcvDEPTH_Z, + gcvDEPTH_W, +} +gceDEPTH_MODE; + +typedef enum _gceWHERE +{ + gcvWHERE_COMMAND, + gcvWHERE_RASTER, + gcvWHERE_PIXEL, +} +gceWHERE; + +typedef enum _gceHOW +{ + gcvHOW_SEMAPHORE = 0x1, + gcvHOW_STALL = 0x2, + gcvHOW_SEMAPHORE_STALL = 0x3, +} +gceHOW; + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Construct a new gcoHAL object. */ +gceSTATUS +gcoHAL_Construct( + IN gctPOINTER Context, + IN gcoOS Os, + OUT gcoHAL * Hal + ); + +/* Destroy an gcoHAL object. */ +gceSTATUS +gcoHAL_Destroy( + IN gcoHAL Hal + ); + +/* Get pointer to gco2D object. */ +gceSTATUS +gcoHAL_Get2DEngine( + IN gcoHAL Hal, + OUT gco2D * Engine + ); + +/* Get pointer to gcoVG object. */ +gceSTATUS +gcoHAL_GetVGEngine( + IN gcoHAL Hal, + OUT gcoVG * Engine + ); + +/* Get pointer to gco3D object. */ +gceSTATUS +gcoHAL_Get3DEngine( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +/* Verify whether the specified feature is available in hardware. */ +gceSTATUS +gcoHAL_IsFeatureAvailable( + IN gcoHAL Hal, + IN gceFEATURE Feature + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gcoHAL_QueryChipIdentity( + IN gcoHAL Hal, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures + ); + +/* Query the minor features of the hardware. */ +gceSTATUS gcoHAL_QueryChipMinorFeatures( + IN gcoHAL Hal, + OUT gctUINT32* NumFeatures, + OUT gctUINT32* ChipMinorFeatures + ); + +/* Query the amount of video memory. */ +gceSTATUS +gcoHAL_QueryVideoMemory( + IN gcoHAL Hal, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Map video memory. */ +gceSTATUS +gcoHAL_MapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + OUT gctPOINTER * Logical + ); + +/* Unmap video memory. */ +gceSTATUS +gcoHAL_UnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a buffer mapped through its physical address. */ +gceSTATUS +gcoHAL_ScheduleUnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a user buffer using event mechanism. */ +gceSTATUS +gcoHAL_ScheduleUnmapUserMemory( + IN gcoHAL Hal, + IN gctPOINTER Info, + IN gctSIZE_T Size, + IN gctUINT32 Address, + IN gctPOINTER Memory + ); + +/* Commit the current command buffer. */ +gceSTATUS +gcoHAL_Commit( + IN gcoHAL Hal, + IN gctBOOL Stall + ); + +/* Query the tile capabilities. */ +gceSTATUS +gcoHAL_QueryTiled( + IN gcoHAL Hal, + OUT gctINT32 * TileWidth2D, + OUT gctINT32 * TileHeight2D, + OUT gctINT32 * TileWidth3D, + OUT gctINT32 * TileHeight3D + ); + +gceSTATUS +gcoHAL_Compact( + IN gcoHAL Hal + ); + +gceSTATUS +gcoHAL_ProfileStart( + IN gcoHAL Hal + ); + +gceSTATUS +gcoHAL_ProfileEnd( + IN gcoHAL Hal, + IN gctCONST_STRING Title + ); + +/* Power Management */ +gceSTATUS +gcoHAL_SetPowerManagementState( + IN gcoHAL Hal, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gcoHAL_QueryPowerManagementState( + IN gcoHAL Hal, + OUT gceCHIPPOWERSTATE *State + ); + +/* Set the filter type for filter blit. */ +gceSTATUS +gcoHAL_SetFilterType( + IN gcoHAL Hal, + IN gceFILTER_TYPE FilterType + ); + +gceSTATUS +gcoHAL_GetDump( + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Call the kernel HAL layer. */ +gceSTATUS +gcoHAL_Call( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Schedule an event. */ +gceSTATUS +gcoHAL_ScheduleEvent( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Destroy a surface. */ +gceSTATUS +gcoHAL_DestroySurface( + IN gcoHAL Hal, + IN gcoSURF Surface + ); + +/* Wait for a signal from GPU. */ +gceSTATUS +gcoHAL_WaitSignalFromGPU( + IN gcoHAL Hal, + IN gctSIGNAL Signal + ); + +/******************************************************************************\ +********************************** gcoOS Object ********************************* +\******************************************************************************/ + +/* Construct a new gcoOS object. */ +gceSTATUS +gcoOS_Construct( + IN gctPOINTER Context, + OUT gcoOS * Os + ); + +/* Destroy an gcoOS object. */ +gceSTATUS +gcoOS_Destroy( + IN gcoOS Os + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gcoOS_GetBaseAddress( + IN gcoOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gcoOS_Allocate( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free allocated memory. */ +gceSTATUS +gcoOS_Free( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate memory. */ +gceSTATUS +gcoOS_AllocateMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free memory. */ +gceSTATUS +gcoOS_FreeMemory( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gcoOS_AllocateContiguous( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gcoOS_FreeContiguous( + IN gcoOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Map user memory. */ +gceSTATUS +gcoOS_MapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gcoOS_UnmapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +/* Device I/O Control call to the kernel HAL layer. */ +gceSTATUS +gcoOS_DeviceControl( + IN gcoOS Os, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + IN gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/* Allocate non paged memory. */ +gceSTATUS gcoOS_AllocateNonPagedMemory( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non paged memory. */ +gceSTATUS gcoOS_FreeNonPagedMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +typedef enum _gceFILE_MODE +{ + gcvFILE_CREATE = 0, + gcvFILE_APPEND, + gcvFILE_READ, + gcvFILE_CREATETEXT, + gcvFILE_APPENDTEXT, + gcvFILE_READTEXT, +} +gceFILE_MODE; + +/* Open a file. */ +gceSTATUS +gcoOS_Open( + IN gcoOS Os, + IN gctCONST_STRING FileName, + IN gceFILE_MODE Mode, + OUT gctFILE * File + ); + +/* Close a file. */ +gceSTATUS +gcoOS_Close( + IN gcoOS Os, + IN gctFILE File + ); + +/* Read data from a file. */ +gceSTATUS +gcoOS_Read( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctPOINTER Data, + OUT gctSIZE_T * ByteRead + ); + +/* Write data to a file. */ +gceSTATUS +gcoOS_Write( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Flush data to a file. */ +gceSTATUS +gcoOS_Flush( + IN gcoOS Os, + IN gctFILE File + ); + +/* Create an endpoint for communication. */ +gceSTATUS +gcoOS_Socket( + IN gcoOS Os, + IN gctINT Domain, + IN gctINT Type, + IN gctINT Protocol, + OUT gctINT *SockFd + ); + +/* Close a socket. */ +gceSTATUS +gcoOS_CloseSocket( + IN gcoOS Os, + IN gctINT SockFd + ); + +/* Initiate a connection on a socket. */ +gceSTATUS +gcoOS_Connect( + IN gcoOS Os, + IN gctINT SockFd, + IN gctCONST_POINTER HostName, + IN gctUINT Port); + +/* Shut down part of connection on a socket. */ +gceSTATUS +gcoOS_Shutdown( + IN gcoOS Os, + IN gctINT SockFd, + IN gctINT How + ); + +/* Send a message on a socket. */ +gceSTATUS +gcoOS_Send( + IN gcoOS Os, + IN gctINT SockFd, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data, + IN gctINT Flags + ); + +/* Initiate a connection on a socket. */ +gceSTATUS +gcoOS_WaitForSend( + IN gcoOS Os, + IN gctINT SockFd, + IN gctINT Seconds, + IN gctINT MicroSeconds); + +/* Get environment variable value. */ +gceSTATUS +gcoOS_GetEnv( + IN gcoOS Os, + IN gctCONST_STRING VarName, + OUT gctSTRING * Value + ); + +typedef enum _gceFILE_WHENCE +{ + gcvFILE_SEEK_SET, + gcvFILE_SEEK_CUR, + gcvFILE_SEEK_END +} +gceFILE_WHENCE; + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_Seek( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Offset, + IN gceFILE_WHENCE Whence + ); + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_SetPos( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Position + ); + +/* Get the current position of a file. */ +gceSTATUS +gcoOS_GetPos( + IN gcoOS Os, + IN gctFILE File, + OUT gctUINT32 * Position + ); + +/* Perform a memory copy. */ +gceSTATUS +gcoOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Perform a memory fill. */ +gceSTATUS +gcoOS_MemFill( + IN gctPOINTER Destination, + IN gctUINT8 Filler, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gcoOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Find the last occurance of a character inside a string. */ +gceSTATUS +gcoOS_StrFindReverse( + IN gctCONST_STRING String, + IN gctINT8 Character, + OUT gctSTRING * Output + ); + +gceSTATUS +gcoOS_StrLen( + IN gctCONST_STRING String, + OUT gctSIZE_T * Length + ); + +gceSTATUS +gcoOS_StrDup( + IN gcoOS Os, + IN gctCONST_STRING String, + OUT gctSTRING * Target + ); + +/* Copy a string. */ +gceSTATUS +gcoOS_StrCopySafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Append a string. */ +gceSTATUS +gcoOS_StrCatSafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Compare two strings. */ +gceSTATUS +gcoOS_StrCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2 + ); + +/* Compare characters of two strings. */ +gceSTATUS +gcoOS_StrNCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2, + IN gctSIZE_T Count + ); + +/* Convert string to float. */ +gceSTATUS +gcoOS_StrToFloat( + IN gctCONST_STRING String, + OUT gctFLOAT * Float + ); + +/* Convert string to integer. */ +gceSTATUS +gcoOS_StrToInt( + IN gctCONST_STRING String, + OUT gctINT * Int + ); + +gceSTATUS +gcoOS_MemCmp( + IN gctCONST_POINTER Memory1, + IN gctCONST_POINTER Memory2, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_PrintStrSafe( + OUT gctSTRING String, + IN gctSIZE_T StringSize, + IN OUT gctUINT * Offset, + IN gctCONST_STRING Format, + ... + ); + +gceSTATUS +gcoOS_PrintStrVSafe( + OUT gctSTRING String, + IN gctSIZE_T StringSize, + IN OUT gctUINT * Offset, + IN gctCONST_STRING Format, + IN gctPOINTER Arguments + ); + +gceSTATUS +gcoOS_LoadLibrary( + IN gcoOS Os, + IN gctCONST_STRING Library, + OUT gctHANDLE * Handle + ); + +gceSTATUS +gcoOS_FreeLibrary( + IN gcoOS Os, + IN gctHANDLE Handle + ); + +gceSTATUS +gcoOS_GetProcAddress( + IN gcoOS Os, + IN gctHANDLE Handle, + IN gctCONST_STRING Name, + OUT gctPOINTER * Function + ); + +gceSTATUS +gcoOS_Compact( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_ProfileStart( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_ProfileEnd( + IN gcoOS Os, + IN gctCONST_STRING Title + ); + +gceSTATUS +gcoOS_SetProfileSetting( + IN gcoOS Os, + IN gctBOOL Enable, + IN gctCONST_STRING FileName + ); + +/* Query the video memory. */ +gceSTATUS +gcoOS_QueryVideoMemory( + IN gcoOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/*----------------------------------------------------------------------------*/ +/*----- Atoms ----------------------------------------------------------------*/ + +typedef struct gcsATOM * gcsATOM_PTR; + +/* Construct an atom. */ +gceSTATUS +gcoOS_AtomConstruct( + IN gcoOS Os, + OUT gcsATOM_PTR * Atom + ); + +/* Destroy an atom. */ +gceSTATUS +gcoOS_AtomDestroy( + IN gcoOS Os, + IN gcsATOM_PTR Atom + ); + +/* Increment an atom. */ +gceSTATUS +gcoOS_AtomIncrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +/* Decrement an atom. */ +gceSTATUS +gcoOS_AtomDecrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +gctHANDLE +gcoOS_GetCurrentProcessID( + void + ); + +/*----------------------------------------------------------------------------*/ +/*----- Time -----------------------------------------------------------------*/ + +/* Get the number of milliseconds since the system started. */ +gctUINT32 +gcoOS_GetTicks( + void + ); + +/* Get time in microseconds. */ +gceSTATUS +gcoOS_GetTime( + gctUINT64_PTR Time + ); + +/* Get CPU usage in microseconds. */ +gceSTATUS +gcoOS_GetCPUTime( + gctUINT64_PTR CPUTime + ); + +/* Get memory usage. */ +gceSTATUS +gcoOS_GetMemoryUsage( + gctUINT32_PTR MaxRSS, + gctUINT32_PTR IxRSS, + gctUINT32_PTR IdRSS, + gctUINT32_PTR IsRSS + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gcoOS_Delay( + IN gcoOS Os, + IN gctUINT32 Delay + ); + +/*----------------------------------------------------------------------------*/ +/*----- Mutexes --------------------------------------------------------------*/ + +/* Create a new mutex. */ +gceSTATUS +gcoOS_CreateMutex( + IN gcoOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gcoOS_DeleteMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gcoOS_AcquireMutex( + IN gcoOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gcoOS_ReleaseMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/*----------------------------------------------------------------------------*/ +/*----- Signals --------------------------------------------------------------*/ + +/* Create a signal. */ +gceSTATUS +gcoOS_CreateSignal( + IN gcoOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gcoOS_DestroySignal( + IN gcoOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gcoOS_Signal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gcoOS_WaitSignal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Write a register. */ +gceSTATUS +gcoOS_WriteRegister( + IN gcoOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Read a register. */ +gceSTATUS +gcoOS_ReadRegister( + IN gcoOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +gceSTATUS +gcoOS_CacheFlush( + IN gcoOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_CacheInvalidate( + IN gcoOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/******************************************************************************* +** gcoMATH object +*/ + +#define gcdPI 3.14159265358979323846f + +gctUINT32 +gcoMATH_Log2in5dot5( + IN gctINT X + ); + +gctFLOAT +gcoMATH_Sine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Cosine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Floor( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Ceiling( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_SquareRoot( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Log2( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Power( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +gctFLOAT +gcoMATH_Modulo( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +gctFLOAT +gcoMATH_Exp( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Absolute( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_ArcCosine( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Tangent( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_UInt2Float( + IN gctUINT X + ); + +gctUINT +gcoMATH_Float2UInt( + IN gctFLOAT X + ); + +gctFLOAT +gcoMATH_Multiply( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +/******************************************************************************\ +**************************** Coordinate Structures ***************************** +\******************************************************************************/ + +typedef struct _gcsPOINT +{ + gctINT32 x; + gctINT32 y; +} +gcsPOINT; + +typedef struct _gcsSIZE +{ + gctINT32 width; + gctINT32 height; +} +gcsSIZE; + +typedef struct _gcsRECT +{ + gctINT32 left; + gctINT32 top; + gctINT32 right; + gctINT32 bottom; +} +gcsRECT; + + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*------------------------------- gcoSURF Common ------------------------------*/ + +/* Color format classes. */ +typedef enum _gceFORMAT_CLASS +{ + gcvFORMAT_CLASS_RGBA = 4500, + gcvFORMAT_CLASS_YUV, + gcvFORMAT_CLASS_INDEX, + gcvFORMAT_CLASS_LUMINANCE, + gcvFORMAT_CLASS_BUMP, + gcvFORMAT_CLASS_DEPTH, +} +gceFORMAT_CLASS; + +/* Special enums for width field in gcsFORMAT_COMPONENT. */ +typedef enum _gceCOMPONENT_CONTROL +{ + gcvCOMPONENT_NOTPRESENT = 0x00, + gcvCOMPONENT_DONTCARE = 0x80, + gcvCOMPONENT_WIDTHMASK = 0x7F, + gcvCOMPONENT_ODD = 0x80 +} +gceCOMPONENT_CONTROL; + +/* Color format component parameters. */ +typedef struct _gcsFORMAT_COMPONENT +{ + gctUINT8 start; + gctUINT8 width; +} +gcsFORMAT_COMPONENT; + +/* RGBA color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_RGBA +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT red; + gcsFORMAT_COMPONENT green; + gcsFORMAT_COMPONENT blue; +} +gcsFORMAT_CLASS_TYPE_RGBA; + +/* YUV color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_YUV +{ + gcsFORMAT_COMPONENT y; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT v; +} +gcsFORMAT_CLASS_TYPE_YUV; + +/* Index color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_INDEX +{ + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_INDEX; + +/* Luminance color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_LUMINANCE; + +/* Bump map color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_BUMP +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT l; + gcsFORMAT_COMPONENT v; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT q; + gcsFORMAT_COMPONENT w; +} +gcsFORMAT_CLASS_TYPE_BUMP; + +/* Depth and stencil format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH +{ + gcsFORMAT_COMPONENT depth; + gcsFORMAT_COMPONENT stencil; +} +gcsFORMAT_CLASS_TYPE_DEPTH; + +/* Format parameters. */ +typedef struct _gcsSURF_FORMAT_INFO +{ + /* Format code and class. */ + gceSURF_FORMAT format; + gceFORMAT_CLASS fmtClass; + + /* The size of one pixel in bits. */ + gctUINT8 bitsPerPixel; + + /* Component swizzle. */ + gceSURF_SWIZZLE swizzle; + + /* Some formats have two neighbour pixels interleaved together. */ + /* To describe such format, set the flag to 1 and add another */ + /* like this one describing the odd pixel format. */ + gctUINT8 interleaved; + + /* Format components. */ + union + { + gcsFORMAT_CLASS_TYPE_BUMP bump; + gcsFORMAT_CLASS_TYPE_RGBA rgba; + gcsFORMAT_CLASS_TYPE_YUV yuv; + gcsFORMAT_CLASS_TYPE_LUMINANCE lum; + gcsFORMAT_CLASS_TYPE_INDEX index; + gcsFORMAT_CLASS_TYPE_DEPTH depth; + } u; +} +gcsSURF_FORMAT_INFO; + +/* Frame buffer information. */ +typedef struct _gcsSURF_FRAMEBUFFER +{ + gctPOINTER logical; + gctUINT width, height; + gctINT stride; + gceSURF_FORMAT format; +} +gcsSURF_FRAMEBUFFER; + +/* Generic pixel component descriptors. */ +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX; + +typedef enum _gceORIENTATION +{ + gcvORIENTATION_TOP_BOTTOM, + gcvORIENTATION_BOTTOM_TOP, +} +gceORIENTATION; + + +/* Construct a new gcoSURF object. */ +gceSTATUS +gcoSURF_Construct( + IN gcoHAL Hal, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +/* Destroy an gcoSURF object. */ +gceSTATUS +gcoSURF_Destroy( + IN gcoSURF Surface + ); + +/* Map user-allocated surface. */ +gceSTATUS +gcoSURF_MapUserSurface( + IN gcoSURF Surface, + IN gctUINT Alignment, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Set the color type of the surface. */ +gceSTATUS +gcoSURF_SetColorType( + IN gcoSURF Surface, + IN gceSURF_COLOR_TYPE ColorType + ); + +/* Get the color type of the surface. */ +gceSTATUS +gcoSURF_GetColorType( + IN gcoSURF Surface, + OUT gceSURF_COLOR_TYPE *ColorType + ); + +/* Set the surface ration angle. */ +gceSTATUS +gcoSURF_SetRotation( + IN gcoSURF Surface, + IN gceSURF_ROTATION Rotation + ); + +/* Verify and return the state of the tile status mechanism. */ +gceSTATUS +gcoSURF_IsTileStatusSupported( + IN gcoSURF Surface + ); + +/* Enable tile status for the specified surface. */ +gceSTATUS +gcoSURF_EnableTileStatus( + IN gcoSURF Surface + ); + +/* Disable tile status for the specified surface. */ +gceSTATUS +gcoSURF_DisableTileStatus( + IN gcoSURF Surface, + IN gctBOOL Decompress + ); + +/* Get surface size. */ +gceSTATUS +gcoSURF_GetSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctUINT * Depth + ); + +/* Get surface aligned sizes. */ +gceSTATUS +gcoSURF_GetAlignedSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctINT * Stride + ); + +/* Get surface type and format. */ +gceSTATUS +gcoSURF_GetFormat( + IN gcoSURF Surface, + OUT gceSURF_TYPE * Type, + OUT gceSURF_FORMAT * Format + ); + +/* Lock the surface. */ +gceSTATUS +gcoSURF_Lock( + IN gcoSURF Surface, + IN OUT gctUINT32 * Address, + IN OUT gctPOINTER * Memory + ); + +/* Unlock the surface. */ +gceSTATUS +gcoSURF_Unlock( + IN gcoSURF Surface, + IN gctPOINTER Memory + ); + +/* Return pixel format parameters. */ +gceSTATUS +gcoSURF_QueryFormat( + IN gceSURF_FORMAT Format, + OUT gcsSURF_FORMAT_INFO_PTR * Info + ); + +/* Compute the color pixel mask. */ +gceSTATUS +gcoSURF_ComputeColorMask( + IN gcsSURF_FORMAT_INFO_PTR Format, + OUT gctUINT32_PTR ColorMask + ); + +/* Flush the surface. */ +gceSTATUS +gcoSURF_Flush( + IN gcoSURF Surface + ); + +/* Fill surface with a value. */ +gceSTATUS +gcoSURF_Fill( + IN gcoSURF Surface, + IN gcsPOINT_PTR Origin, + IN gcsSIZE_PTR Size, + IN gctUINT32 Value, + IN gctUINT32 Mask + ); + +/* Alpha blend two surfaces together. */ +gceSTATUS +gcoSURF_Blend( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrig, + IN gcsPOINT_PTR DestOrigin, + IN gcsSIZE_PTR Size, + IN gceSURF_BLEND_MODE Mode + ); + +/* Create a new gcoSURF wrapper object. */ +gceSTATUS +gcoSURF_ConstructWrapper( + IN gcoHAL Hal, + OUT gcoSURF * Surface + ); + +/* Set the underlying buffer for the surface wrapper. */ +gceSTATUS +gcoSURF_SetBuffer( + IN gcoSURF Surface, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gctUINT Stride, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Set the size of the surface in pixels and map the underlying buffer. */ +gceSTATUS +gcoSURF_SetWindow( + IN gcoSURF Surface, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height + ); + +/* Increase reference count of the surface. */ +gceSTATUS +gcoSURF_ReferenceSurface( + IN gcoSURF Surface + ); + +/* Get surface reference count. */ +gceSTATUS +gcoSURF_QueryReferenceCount( + IN gcoSURF Surface, + OUT gctINT32 * ReferenceCount + ); + +/* Set surface orientation. */ +gceSTATUS +gcoSURF_SetOrientation( + IN gcoSURF Surface, + IN gceORIENTATION Orientation + ); + +/* Query surface orientation. */ +gceSTATUS +gcoSURF_QueryOrientation( + IN gcoSURF Surface, + OUT gceORIENTATION * Orientation + ); + +/*Reset the hal member of a surface*/ +gceSTATUS +gcoSURF_ResetHal( + IN gcoSURF Surface, + IN gcoHAL Hal + ); + +/******************************************************************************\ +********************************* gcoDUMP Object ******************************** +\******************************************************************************/ + +/* Construct a new gcoDUMP object. */ +gceSTATUS +gcoDUMP_Construct( + IN gcoOS Os, + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Destroy a gcoDUMP object. */ +gceSTATUS +gcoDUMP_Destroy( + IN gcoDUMP Dump + ); + +/* Enable/disable dumping. */ +gceSTATUS +gcoDUMP_Control( + IN gcoDUMP Dump, + IN gctSTRING FileName + ); + +gceSTATUS +gcoDUMP_IsEnabled( + IN gcoDUMP Dump, + OUT gctBOOL * Enabled + ); + +/* Add surface. */ +gceSTATUS +gcoDUMP_AddSurface( + IN gcoDUMP Dump, + IN gctINT32 Width, + IN gctINT32 Height, + IN gceSURF_FORMAT PixelFormat, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount + ); + +/* Mark the beginning of a frame. */ +gceSTATUS +gcoDUMP_FrameBegin( + IN gcoDUMP Dump + ); + +/* Mark the end of a frame. */ +gceSTATUS +gcoDUMP_FrameEnd( + IN gcoDUMP Dump + ); + +/* Dump data. */ +gceSTATUS +gcoDUMP_DumpData( + IN gcoDUMP Dump, + IN gceDUMP_TAG Type, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Delete an address. */ +gceSTATUS +gcoDUMP_Delete( + IN gcoDUMP Dump, + IN gctUINT32 Address + ); + +/******************************************************************************\ +******************************* gcsRECT Structure ****************************** +\******************************************************************************/ + +/* Initialize rectangle structure. */ +gceSTATUS +gcsRECT_Set( + OUT gcsRECT_PTR Rect, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Return the width of the rectangle. */ +gceSTATUS +gcsRECT_Width( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Width + ); + +/* Return the height of the rectangle. */ +gceSTATUS +gcsRECT_Height( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Height + ); + +/* Ensure that top left corner is to the left and above the right bottom. */ +gceSTATUS +gcsRECT_Normalize( + IN OUT gcsRECT_PTR Rect + ); + +/* Compare two rectangles. */ +gceSTATUS +gcsRECT_IsEqual( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * Equal + ); + +/* Compare the sizes of two rectangles. */ +gceSTATUS +gcsRECT_IsOfEqualSize( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * EqualSize + ); + + +/******************************************************************************\ +**************************** gcsBOUNDARY Structure ***************************** +\******************************************************************************/ + +typedef struct _gcsBOUNDARY +{ + gctINT x; + gctINT y; + gctINT width; + gctINT height; +} +gcsBOUNDARY; + +/******************************************************************************\ +********************************* gcoHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gcoHEAP * gcoHEAP; + +/* Construct a new gcoHEAP object. */ +gceSTATUS +gcoHEAP_Construct( + IN gcoOS Os, + IN gctSIZE_T AllocationSize, + OUT gcoHEAP * Heap + ); + +/* Destroy an gcoHEAP object. */ +gceSTATUS +gcoHEAP_Destroy( + IN gcoHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gcoHEAP_Allocate( + IN gcoHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +/* Free memory. */ +gceSTATUS +gcoHEAP_Free( + IN gcoHEAP Heap, + IN gctPOINTER Node + ); + +/* Profile the heap. */ +gceSTATUS +gcoHEAP_ProfileStart( + IN gcoHEAP Heap + ); + +gceSTATUS +gcoHEAP_ProfileEnd( + IN gcoHEAP Heap, + IN gctCONST_STRING Title + ); + +#if defined gcdHAL_TEST +gceSTATUS +gcoHEAP_Test( + IN gcoHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ); +#endif + +/******************************************************************************\ +******************************* Debugging Macros ******************************* +\******************************************************************************/ + +void +gcoOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gcoOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gcoOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gcoOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gcoOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +/******************************************************************************* +** +** gcmFATAL +** +** Print a message to the debugger and execute a break point. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmFATAL gcoOS_DebugFatal +# define gcmkFATAL gckOS_DebugFatal +#elif gcdHAS_ELLIPSES +# define gcmFATAL(...) +# define gcmkFATAL(...) +#else + gcmINLINE static void + __dummy_fatal( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmFATAL __dummy_fatal +# define gcmkFATAL __dummy_fatal +#endif + +#define gcmENUM2TEXT(e) case e: return #e + +/******************************************************************************* +** +** gcmTRACE +** +** Print a message to the debugfer if the correct level has been set. In +** retail mode this macro does nothing. +** +** ARGUMENTS: +** +** level Level of message. +** message Message. +** ... Optional arguments. +*/ +#define gcvLEVEL_NONE -1 +#define gcvLEVEL_ERROR 0 +#define gcvLEVEL_WARNING 1 +#define gcvLEVEL_INFO 2 +#define gcvLEVEL_VERBOSE 3 + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); +void + +gcoOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmTRACE gcoOS_DebugTrace +# define gcmkTRACE gckOS_DebugTrace +#elif gcdHAS_ELLIPSES +# define gcmTRACE(...) +# define gcmkTRACE(...) +#else + gcmINLINE static void + __dummy_trace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmTRACE __dummy_trace +# define gcmkTRACE __dummy_trace +#endif + +/* Debug zones. */ +#define gcvZONE_OS (1 << 0) +#define gcvZONE_HARDWARE (1 << 1) +#define gcvZONE_HEAP (1 << 2) + +/* Kernel zones. */ +#define gcvZONE_KERNEL (1 << 3) +#define gcvZONE_VIDMEM (1 << 4) +#define gcvZONE_COMMAND (1 << 5) +#define gcvZONE_DRIVER (1 << 6) +#define gcvZONE_CMODEL (1 << 7) +#define gcvZONE_MMU (1 << 8) +#define gcvZONE_EVENT (1 << 9) +#define gcvZONE_DEVICE (1 << 10) + +/* User zones. */ +#define gcvZONE_HAL (1 << 3) +#define gcvZONE_BUFFER (1 << 4) +#define gcvZONE_CONTEXT (1 << 5) +#define gcvZONE_SURFACE (1 << 6) +#define gcvZONE_INDEX (1 << 7) +#define gcvZONE_STREAM (1 << 8) +#define gcvZONE_TEXTURE (1 << 9) +#define gcvZONE_2D (1 << 10) +#define gcvZONE_3D (1 << 11) +#define gcvZONE_COMPILER (1 << 12) +#define gcvZONE_MEMORY (1 << 13) +#define gcvZONE_STATE (1 << 14) +#define gcvZONE_AUX (1 << 15) + +/* API definitions. */ +#define gcvZONE_API_HAL (0 << 28) +#define gcvZONE_API_EGL (1 << 28) +#define gcvZONE_API_ES11 (2 << 28) +#define gcvZONE_API_ES20 (3 << 28) +#define gcvZONE_API_VG11 (4 << 28) +#define gcvZONE_API_GL (5 << 28) +#define gcvZONE_API_DFB (6 << 28) +#define gcvZONE_API_GDI (7 << 28) +#define gcvZONE_API_D3D (8 << 28) + +#define gcmZONE_GET_API(zone) ((zone) >> 28) +#define gcdZONE_MASK 0x0FFFFFFF + +/* Handy zones. */ +#define gcvZONE_NONE 0 +#define gcvZONE_ALL gcdZONE_MASK + +/******************************************************************************* +** +** gcmTRACE_ZONE +** +** Print a message to the debugger if the correct level and zone has been +** set. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** Level Level of message. +** Zone Zone of message. +** Message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +#if gcdDEBUG +# define gcmTRACE_ZONE gcoOS_DebugTraceZone +# define gcmkTRACE_ZONE gckOS_DebugTraceZone +#elif gcdHAS_ELLIPSES +# define gcmTRACE_ZONE(...) +# define gcmkTRACE_ZONE(...) +#else + gcmINLINE static void + __dummy_trace_zone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmTRACE_ZONE __dummy_trace_zone +# define gcmkTRACE_ZONE __dummy_trace_zone +#endif + +/******************************************************************************\ +******************************** Logging Macros ******************************** +\******************************************************************************/ + +#define gcdHEADER_LEVEL gcvLEVEL_VERBOSE + +#define gcmHEADER() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmHEADER_ARG(Text, ...) \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_header_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmHEADER_ARG __dummy_header_arg +#endif + +#define gcmFOOTER() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d", \ + __FUNCTION__, __LINE__, status) + +#define gcmFOOTER_NO() \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmFOOTER_ARG(Text, ...) \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_footer_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmFOOTER_ARG __dummy_footer_arg +#endif + +#define gcmkHEADER() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmkHEADER_ARG(Text, ...) \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_kheader_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkHEADER_ARG __dummy_kheader_arg +#endif + +#define gcmkFOOTER() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d", \ + __FUNCTION__, __LINE__, status) + +#define gcmkFOOTER_NO() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__) + +#if gcdHAS_ELLIPSES +# define gcmkFOOTER_ARG(Text, ...) \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, \ + __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_kfooter_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkFOOTER_ARG __dummy_kfooter_arg +#endif + +#define gcmOPT_VALUE(ptr) (((ptr) == gcvNULL) ? 0 : *(ptr)) +#define gcmOPT_POINTER(ptr) (((ptr) == gcvNULL) ? gcvNULL : *(ptr)) +#define gcmOPT_STRING(ptr) (((ptr) == gcvNULL) ? "(nil)" : (ptr)) + +void +gcoOS_Print( + IN gctCONST_STRING Message, + ... + ); +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ); +#define gcmPRINT gcoOS_Print +#define gcmkPRINT gckOS_Print + +/******************************************************************************* +** +** gcmDUMP +** +** Print a dump message. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP + gceSTATUS + gcfDump( + IN gcoOS Os, + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP gcfDump +#elif gcdHAS_ELLIPSES +# define gcmDUMP(...) +#else + gcmINLINE static void + __dummy_dump( + IN gcoOS Os, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP __dummy_dump +#endif + +/******************************************************************************* +** +** gcmDUMP_DATA +** +** Add data to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP + gceSTATUS + gcfDumpData( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_DATA gcfDumpData +#elif gcdHAS_ELLIPSES +# define gcmDUMP_DATA(...) +#else + gcmINLINE static void + __dummy_dump_data( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_DATA __dummy_dump_data +#endif + +/******************************************************************************* +** +** gcmDUMP_BUFFER +** +** Print a buffer to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctUINT32 Physical +** Physical address of buffer. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctUINT32 Offset +** Offset into buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP +gceSTATUS +gcfDumpBuffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_BUFFER gcfDumpBuffer +#elif gcdHAS_ELLIPSES +# define gcmDUMP_BUFFER(...) +#else + gcmINLINE static void + __dummy_dump_buffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_BUFFER __dummy_dump_buffer +#endif + +/******************************************************************************* +** +** gcmDUMP_API +** +** Print a dump message for a high level API prefixed by the function name. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpApi( + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP_API gcfDumpApi +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API(...) +#else + gcmINLINE static void + __dummy_dump_api( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP_API __dummy_dump_api +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY +** +** Print an array of data. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Size. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArray( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ); +# define gcmDUMP_API_ARRAY gcfDumpArray +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY(...) +#else + gcmINLINE static void + __dummy_dump_api_array( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ) + { + } +# define gcmDUMP_API_ARRAY __dummy_dump_api_array +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY_TOKEN +** +** Print an array of data terminated by a token. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Termination. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArrayToken( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ); +# define gcmDUMP_API_ARRAY_TOKEN gcfDumpArrayToken +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY_TOKEN(...) +#else + gcmINLINE static void + __dummy_dump_api_array_token( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ) + { + } +# define gcmDUMP_API_ARRAY_TOKEN __dummy_dump_api_array_token +#endif + +/******************************************************************************* +** +** gcmTRACE_RELEASE +** +** Print a message to the shader debugger. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +#define gcmTRACE_RELEASE gcoOS_DebugShaderTrace + +void +gcoOS_DebugShaderTrace( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_SetDebugShaderFiles( + IN gctCONST_STRING VSFileName, + IN gctCONST_STRING FSFileName + ); + +void +gcoOS_SetDebugShaderFileType( + IN gctUINT32 ShaderType + ); + +/******************************************************************************* +** +** gcmBREAK +** +** Break into the debugger. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** None. +*/ + +void +gcoOS_DebugBreak( + void + ); + +void +gckOS_DebugBreak( + void + ); + +#if gcdDEBUG +# define gcmBREAK gcoOS_DebugBreak +# define gcmkBREAK gckOS_DebugBreak +#else +# define gcmBREAK() +# define gcmkBREAK() +#endif + +/******************************************************************************* +** +** gcmASSERT +** +** Evaluate an expression and break into the debugger if the expression +** evaluates to false. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcdDEBUG +# define _gcmASSERT(prefix, exp) \ + do \ + { \ + if (!(exp)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ASSERT at %s(%d) in " __FILE__, \ + __FUNCTION__, __LINE__); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + "(%s)", #exp); \ + prefix##BREAK(); \ + } \ + } \ + while (gcvFALSE) +# define gcmASSERT(exp) _gcmASSERT(gcm, exp) +# define gcmkASSERT(exp) _gcmASSERT(gcmk, exp) +#else +# define gcmASSERT(exp) +# define gcmkASSERT(exp) +#endif + +/******************************************************************************* +** +** gcmVERIFY +** +** Verify if an expression returns true. If the expression does not +** evaluates to true, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcdDEBUG +# define gcmVERIFY(exp) gcmASSERT(exp) +# define gcmkVERIFY(exp) gcmkASSERT(exp) +#else +# define gcmVERIFY(exp) exp +# define gcmkVERIFY(exp) exp +#endif + +/******************************************************************************* +** +** gcmVERIFY_OK +** +** Verify a fucntion returns gcvSTATUS_OK. If the function does not return +** gcvSTATUS_OK, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ + +void +gcoOS_Verify( + IN gceSTATUS Status + ); + +void +gckOS_Verify( + IN gceSTATUS Status + ); + +#if gcdDEBUG +# define gcmVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + gcoOS_Verify(verifyStatus); \ + gcmASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +# define gcmkVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + gckOS_Verify(verifyStatus); \ + gcmkASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +#else +# define gcmVERIFY_OK(func) func +# define gcmkVERIFY_OK(func) func +#endif + +/******************************************************************************* +** +** gcmERR_BREAK +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_BREAK(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_BREAK: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + break; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_BREAK(func) _gcmERR_BREAK(gcm, func) +#define gcmkERR_BREAK(func) _gcmERR_BREAK(gcmk, func) + +/******************************************************************************* +** +** gcmERR_RETURN +** +** Executes a return on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_RETURN(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_RETURN: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + return status; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_RETURN(func) _gcmERR_RETURN(gcm, func) +#define gcmkERR_RETURN(func) _gcmERR_RETURN(gcmk, func) + +/******************************************************************************* +** +** gcmONERROR +** +** Jump to the error handler in case there is an error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmONERROR(prefix, func) \ + do \ + { \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ONERROR: status=%d @ %s(%d) in " __FILE__, \ + status, __FUNCTION__, __LINE__); \ + goto OnError; \ + } \ + } \ + while (gcvFALSE) +#define gcmONERROR(func) _gcmONERROR(gcm, func) +#define gcmkONERROR(func) _gcmONERROR(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_LOCK +** +** Verifies whether the surface is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_LOCK(surfaceInfo) \ + if (!surfaceInfo->node.valid) \ + { \ + status = gcvSTATUS_MEMORY_UNLOCKED; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmVERIFY_NODE_LOCK +** +** Verifies whether the surface node is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_NODE_LOCK(surfaceNode) \ + if (!surfaceNode->valid) \ + { \ + status = gcvSTATUS_MEMORY_UNLOCKED; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmBADOBJECT_BREAK +** +** Executes a break statement on bad object. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#define gcmBADOBJECT_BREAK(obj, t) \ + if ((obj == gcvNULL) \ + || (((gcsOBJECT *)(obj))->type != t) \ + ) \ + { \ + status = gcvSTATUS_INVALID_OBJECT; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmCHECK_STATUS +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmCHECK_STATUS(prefix, func) \ + do \ + { \ + last = func; \ + if (gcmIS_ERROR(last)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "CHECK_STATUS: status=%d @ %s(%d) in " __FILE__, \ + last, __FUNCTION__, __LINE__); \ + status = last; \ + } \ + } \ + while (gcvFALSE) +#define gcmCHECK_STATUS(func) _gcmCHECK_STATUS(gcm, func) +#define gcmkCHECK_STATUS(func) _gcmCHECK_STATUS(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_ARGUMENT(prefix, arg) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \ + return gcvSTATUS_INVALID_ARGUMENT; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) +# define gcmkVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcmk, arg) +#else +# define gcmVERIFY_ARGUMENT(arg) +# define gcmkVERIFY_ARGUMENT(arg) +#endif + +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT_RETURN +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("value=%d", value); \ + return value; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value) +# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value) +#else +# define gcmVERIFY_ARGUMENT_RETURN(arg, value) +# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) +#endif +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_base_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_compiler.h b/kernel_drivers/v2/hal/inc/gc_hal_compiler.h new file mode 100644 index 0000000..d237cc3 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_compiler.h @@ -0,0 +1,1955 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file the defines the front- and back-end compilers, as well as the +** objects they use. +*/ + +#ifndef __gc_hal_compiler_h_ +#define __gc_hal_compiler_h_ + +#include "gc_hal_types.h" +#include "gc_hal_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +|******************************* SHADER LANGUAGE ******************************| +\******************************************************************************/ + +/* Possible shader language opcodes. */ +typedef enum _gcSL_OPCODE +{ + gcSL_NOP, /* 0x00 */ + gcSL_MOV, /* 0x01 */ + gcSL_SAT, /* 0x02 */ + gcSL_DP3, /* 0x03 */ + gcSL_DP4, /* 0x04 */ + gcSL_ABS, /* 0x05 */ + gcSL_JMP, /* 0x06 */ + gcSL_ADD, /* 0x07 */ + gcSL_MUL, /* 0x08 */ + gcSL_RCP, /* 0x09 */ + gcSL_SUB, /* 0x0A */ + gcSL_KILL, /* 0x0B */ + gcSL_TEXLD, /* 0x0C */ + gcSL_CALL, /* 0x0D */ + gcSL_RET, /* 0x0E */ + gcSL_NORM, /* 0x0F */ + gcSL_MAX, /* 0x10 */ + gcSL_MIN, /* 0x11 */ + gcSL_POW, /* 0x12 */ + gcSL_RSQ, /* 0x13 */ + gcSL_LOG, /* 0x14 */ + gcSL_FRAC, /* 0x15 */ + gcSL_FLOOR, /* 0x16 */ + gcSL_CEIL, /* 0x17 */ + gcSL_CROSS, /* 0x18 */ + gcSL_TEXLDP, /* 0x19 */ + gcSL_TEXBIAS, /* 0x1A */ + gcSL_TEXGRAD, /* 0x1B */ + gcSL_TEXLOD, /* 0x1C */ + gcSL_SIN, /* 0x1D */ + gcSL_COS, /* 0x1E */ + gcSL_TAN, /* 0x1F */ + gcSL_EXP, /* 0x20 */ + gcSL_SIGN, /* 0x21 */ + gcSL_STEP, /* 0x22 */ + gcSL_SQRT, /* 0x23 */ + gcSL_ACOS, /* 0x24 */ + gcSL_ASIN, /* 0x25 */ + gcSL_ATAN, /* 0x26 */ + gcSL_SET, /* 0x27 */ + gcSL_DSX, /* 0x28 */ + gcSL_DSY, /* 0x29 */ + gcSL_FWIDTH, /* 0x2A */ +} +gcSL_OPCODE; + +typedef enum _gcSL_FORMAT +{ + gcSL_FLOAT, /* 0 */ + gcSL_INTEGER, /* 1 */ + gcSL_BOOLEAN, /* 2 */ +} +gcSL_FORMAT; + +/* Destination write enable bits. */ +typedef enum _gcSL_ENABLE +{ + gcSL_ENABLE_X = 0x1, + gcSL_ENABLE_Y = 0x2, + gcSL_ENABLE_Z = 0x4, + gcSL_ENABLE_W = 0x8, + /* Combinations. */ + gcSL_ENABLE_XY = gcSL_ENABLE_X | gcSL_ENABLE_Y, + gcSL_ENABLE_XYZ = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_XYZW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XYW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_XZ = gcSL_ENABLE_X | gcSL_ENABLE_Z, + gcSL_ENABLE_XZW = gcSL_ENABLE_X | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XW = gcSL_ENABLE_X | gcSL_ENABLE_W, + gcSL_ENABLE_YZ = gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_YZW = gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_YW = gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_ZW = gcSL_ENABLE_Z | gcSL_ENABLE_W, +} +gcSL_ENABLE; + +/* Possible indices. */ +typedef enum _gcSL_INDEXED +{ + gcSL_NOT_INDEXED, /* 0 */ + gcSL_INDEXED_X, /* 1 */ + gcSL_INDEXED_Y, /* 2 */ + gcSL_INDEXED_Z, /* 3 */ + gcSL_INDEXED_W, /* 4 */ +} +gcSL_INDEXED; + +/* Opcode conditions. */ +typedef enum _gcSL_CONDITION +{ + gcSL_ALWAYS, /* 0x0 */ + gcSL_NOT_EQUAL, /* 0x1 */ + gcSL_LESS_OR_EQUAL, /* 0x2 */ + gcSL_LESS, /* 0x3 */ + gcSL_EQUAL, /* 0x4 */ + gcSL_GREATER, /* 0x5 */ + gcSL_GREATER_OR_EQUAL, /* 0x6 */ + gcSL_AND, /* 0x7 */ + gcSL_OR, /* 0x8 */ + gcSL_XOR, /* 0x9 */ +} +gcSL_CONDITION; + +/* Possible source operand types. */ +typedef enum _gcSL_TYPE +{ + gcSL_NONE, /* 0x0 */ + gcSL_TEMP, /* 0x1 */ + gcSL_ATTRIBUTE, /* 0x2 */ + gcSL_UNIFORM, /* 0x3 */ + gcSL_SAMPLER, /* 0x4 */ + gcSL_CONSTANT, /* 0x5 */ + gcSL_OUTPUT, /* 0x6 */ + gcSL_PHYSICAL, /* 0x7 */ +} +gcSL_TYPE; + +/* Swizzle generator macro. */ +#define gcmSWIZZLE(Component1, Component2, Component3, Component4) \ +( \ + (gcSL_SWIZZLE_ ## Component1 << 0) | \ + (gcSL_SWIZZLE_ ## Component2 << 2) | \ + (gcSL_SWIZZLE_ ## Component3 << 4) | \ + (gcSL_SWIZZLE_ ## Component4 << 6) \ +) + +/* Possible swizzle values. */ +typedef enum _gcSL_SWIZZLE +{ + gcSL_SWIZZLE_X, /* 0x0 */ + gcSL_SWIZZLE_Y, /* 0x1 */ + gcSL_SWIZZLE_Z, /* 0x2 */ + gcSL_SWIZZLE_W, /* 0x3 */ + /* Combinations. */ + gcSL_SWIZZLE_XXXX = gcmSWIZZLE(X, X, X, X), + gcSL_SWIZZLE_YYYY = gcmSWIZZLE(Y, Y, Y, Y), + gcSL_SWIZZLE_ZZZZ = gcmSWIZZLE(Z, Z, Z, Z), + gcSL_SWIZZLE_WWWW = gcmSWIZZLE(W, W, W, W), + gcSL_SWIZZLE_XYYY = gcmSWIZZLE(X, Y, Y, Y), + gcSL_SWIZZLE_XZZZ = gcmSWIZZLE(X, Z, Z, Z), + gcSL_SWIZZLE_XWWW = gcmSWIZZLE(X, W, W, W), + gcSL_SWIZZLE_YZZZ = gcmSWIZZLE(Y, Z, Z, Z), + gcSL_SWIZZLE_YWWW = gcmSWIZZLE(Y, W, W, W), + gcSL_SWIZZLE_ZWWW = gcmSWIZZLE(Z, W, W, W), + gcSL_SWIZZLE_XYZZ = gcmSWIZZLE(X, Y, Z, Z), + gcSL_SWIZZLE_XYWW = gcmSWIZZLE(X, Y, W, W), + gcSL_SWIZZLE_XZWW = gcmSWIZZLE(X, Z, W, W), + gcSL_SWIZZLE_YZWW = gcmSWIZZLE(Y, Z, W, W), + gcSL_SWIZZLE_XXYZ = gcmSWIZZLE(X, X, Y, Z), + gcSL_SWIZZLE_XYZW = gcmSWIZZLE(X, Y, Z, W), + gcSL_SWIZZLE_XYXY = gcmSWIZZLE(X, Y, X, Y), +} +gcSL_SWIZZLE; + + +/******************************************************************************\ +|*********************************** SHADERS **********************************| +\******************************************************************************/ + +/* Shader types. */ +#define gcSHADER_TYPE_UNKNOWN 0 +#define gcSHADER_TYPE_VERTEX 1 +#define gcSHADER_TYPE_FRAGMENT 2 + +/* gcSHADER objects. */ +typedef struct _gcSHADER * gcSHADER; +typedef struct _gcATTRIBUTE * gcATTRIBUTE; +typedef struct _gcUNIFORM * gcUNIFORM; +typedef struct _gcOUTPUT * gcOUTPUT; +typedef struct _gcsFUNCTION * gcFUNCTION; +typedef struct _gcsHINT * gcsHINT_PTR; +typedef struct _gcSHADER_PROFILER * gcSHADER_PROFILER; +typedef struct _gcVARIABLE * gcVARIABLE; + +/* gcSHADER_TYPE enumeration. */ +typedef enum _gcSHADER_TYPE +{ + gcSHADER_FLOAT_X1, /* 0x00 */ + gcSHADER_FLOAT_X2, /* 0x01 */ + gcSHADER_FLOAT_X3, /* 0x02 */ + gcSHADER_FLOAT_X4, /* 0x03 */ + gcSHADER_FLOAT_2X2, /* 0x04 */ + gcSHADER_FLOAT_3X3, /* 0x05 */ + gcSHADER_FLOAT_4X4, /* 0x06 */ + gcSHADER_BOOLEAN_X1, /* 0x07 */ + gcSHADER_BOOLEAN_X2, /* 0x08 */ + gcSHADER_BOOLEAN_X3, /* 0x09 */ + gcSHADER_BOOLEAN_X4, /* 0x0A */ + gcSHADER_INTEGER_X1, /* 0x0B */ + gcSHADER_INTEGER_X2, /* 0x0C */ + gcSHADER_INTEGER_X3, /* 0x0D */ + gcSHADER_INTEGER_X4, /* 0x0E */ + gcSHADER_SAMPLER_1D, /* 0x0F */ + gcSHADER_SAMPLER_2D, /* 0x10 */ + gcSHADER_SAMPLER_3D, /* 0x11 */ + gcSHADER_SAMPLER_CUBIC, /* 0x12 */ + gcSHADER_FIXED_X1, /* 0x13 */ + gcSHADER_FIXED_X2, /* 0x14 */ + gcSHADER_FIXED_X3, /* 0x15 */ + gcSHADER_FIXED_X4, /* 0x16 */ +} +gcSHADER_TYPE; + +/* Shader flags. */ +typedef enum _gceSHADER_FLAGS +{ + gcvSHADER_DEAD_CODE = 0x01, + gcvSHADER_RESOURCE_USAGE = 0x02, + gcvSHADER_OPTIMIZER = 0x04, + gcvSHADER_USE_GL_Z = 0x08, + gcvSHADER_USE_GL_POSITION = 0x10, + gcvSHADER_USE_GL_FACE = 0x20, + gcvSHADER_USE_GL_POINT_COORD = 0x40, +} +gceSHADER_FLAGS; + +/* Function argument qualifier */ +typedef enum _gceINPUT_OUTPUT +{ + gcvFUNCTION_INPUT, + gcvFUNCTION_OUTPUT, + gcvFUNCTION_INOUT +} +gceINPUT_OUTPUT; + +/******************************************************************************* +** gcSHADER_Construct +******************************************************************************** +** +** Construct a new gcSHADER object. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Type of gcSHADER object to cerate. 'ShaderType' can be one of the +** following: +** +** gcSHADER_TYPE_VERTEX Vertex shader. +** gcSHADER_TYPE_FRAGMENT Fragment shader. +** +** OUTPUT: +** +** gcSHADER * Shader +** Pointer to a variable receiving the gcSHADER object pointer. +*/ +gceSTATUS +gcSHADER_Construct( + IN gcoHAL Hal, + IN gctINT ShaderType, + OUT gcSHADER * Shader + ); + +/******************************************************************************* +** gcSHADER_Destroy +******************************************************************************** +** +** Destroy a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Destroy( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_Load +******************************************************************************** +** +** Load a gcSHADER object from a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer containg the shader data to load. +** +** gctSIZE_T BufferSize +** Number of bytes inside the binary buffer pointed to by 'Buffer'. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Load( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN gctSIZE_T BufferSize + ); + +/******************************************************************************* +** gcSHADER_Save +******************************************************************************** +** +** Save a gcSHADER object to a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer to be used as storage for the gcSHADER +** object. If 'Buffer' is gcvNULL, the gcSHADER object will not be saved, +** but the number of bytes required to hold the binary output for the +** gcSHADER object will be returned. +** +** gctSIZE_T * BufferSize +** Pointer to a variable holding the number of bytes allocated in +** 'Buffer'. Only valid if 'Buffer' is not gcvNULL. +** +** OUTPUT: +** +** gctSIZE_T * BufferSize +** Pointer to a variable receiving the number of bytes required to hold +** the binary form of the gcSHADER object. +*/ +gceSTATUS +gcSHADER_Save( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN OUT gctSIZE_T * BufferSize + ); + +/******************************************************************************* +** gcSHADER_ReallocateAttributes +** +** Reallocate an array of pointers to gcATTRIBUTE objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateAttributes( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddAttribute +******************************************************************************** +** +** Add an attribute to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the attribute to add. +** +** gcSHADER_TYPE Type +** Type of the attribute to add. +** +** gctSIZE_T Length +** Array length of the attribute to add. 'Length' must be at least 1. +** +** gctBOOL IsTexture +** gcvTRUE if the attribute is used as a texture coordinate, gcvFALSE if not. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_AddAttribute( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctBOOL IsTexture, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_GetAttributeCount +******************************************************************************** +** +** Get the number of attributes for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of attributes. +*/ +gceSTATUS +gcSHADER_GetAttributeCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetAttribute +******************************************************************************** +** +** Get the gcATTRIBUTE object poniter for an indexed attribute for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the attribute to retrieve. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_GetAttribute( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_GetPositionAttribute +******************************************************************************** +** +** Get the gcATTRIBUTE object pointer for the attribute that defines the +** position. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctUINT * Index +** Pointer to a variable receiving the index of te gcATTRIBUTE object +** used as a position. +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_GetPositionAttribute( + IN gcSHADER Shader, + OUT gctUINT * Index, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_ReallocateUniforms +** +** Reallocate an array of pointers to gcUNIFORM objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateUniforms( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddUniform +******************************************************************************** +** +** Add an uniform to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the uniform to add. +** +** gcSHADER_TYPE Type +** Type of the uniform to add. +** +** gctSIZE_T Length +** Array length of the uniform to add. 'Length' must be at least 1. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_AddUniform( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_GetUniformCount +******************************************************************************** +** +** Get the number of uniforms for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of uniforms. +*/ +gceSTATUS +gcSHADER_GetUniformCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetUniform +******************************************************************************** +** +** Get the gcUNIFORM object pointer for an indexed uniform for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the uniform to retrieve. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_GetUniform( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_ReallocateOutputs +** +** Reallocate an array of pointers to gcOUTPUT objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateOutputs( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddOutput +******************************************************************************** +** +** Add an output to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the output to add. +** +** gcSHADER_TYPE Type +** Type of the output to add. +** +** gctSIZE_T Length +** Array length of the output to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the output value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOutput( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + +gceSTATUS +gcSHADER_AddOutputIndexed( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gctSIZE_T Index, + IN gctUINT16 TempIndex + ); + +/******************************************************************************* +** gcSHADER_GetOutputCount +******************************************************************************** +** +** Get the number of outputs for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of outputs. +*/ +gceSTATUS +gcSHADER_GetOutputCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetOutput +******************************************************************************** +** +** Get the gcOUTPUT object pointer for an indexed output for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of output to retrieve. +** +** OUTPUT: +** +** gcOUTPUT * Output +** Pointer to a variable receiving the gcOUTPUT object pointer. +*/ +gceSTATUS +gcSHADER_GetOutput( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcOUTPUT * Output + ); + +/******************************************************************************* +** gcSHADER_ReallocateVariables +** +** Reallocate an array of pointers to gcVARIABLE objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateVariables( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddVariable +******************************************************************************** +** +** Add a variable to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the variable to add. +** +** gcSHADER_TYPE Type +** Type of the variable to add. +** +** gctSIZE_T Length +** Array length of the variable to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the variable value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddVariable( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + +/******************************************************************************* +** gcSHADER_GetVariableCount +******************************************************************************** +** +** Get the number of variables for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of variables. +*/ +gceSTATUS +gcSHADER_GetVariableCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetVariable +******************************************************************************** +** +** Get the gcVARIABLE object pointer for an indexed variable for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of variable to retrieve. +** +** OUTPUT: +** +** gcVARIABLE * Variable +** Pointer to a variable receiving the gcVARIABLE object pointer. +*/ +gceSTATUS +gcSHADER_GetVariable( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcVARIABLE * Variable + ); + +/******************************************************************************* +** gcSHADER_AddOpcode +******************************************************************************** +** +** Add an opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the target +** of the opcode. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcode( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddOpcode2( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeIndexed +******************************************************************************** +** +** Add an opcode to a gcSHADER object that writes to an dynamically indexed +** target. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the +** target of the opcode. +** +** gcSL_INDEXED Mode +** Location of the dynamic index inside the temporary register. Valid +** values can be: +** +** gcSL_INDEXED_X - Use x component of the temporary register. +** gcSL_INDEXED_Y - Use y component of the temporary register. +** gcSL_INDEXED_Z - Use z component of the temporary register. +** gcSL_INDEXED_W - Use w component of the temporary register. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeIndexed( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditional +******************************************************************************** +** +** Add an conditional opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition that needs to evaluate to gcvTRUE in order for the opcode to +** execute. +** +** gctUINT Label +** Target label if 'Condition' evaluates to gcvTRUE. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditional( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddLabel +******************************************************************************** +** +** Define a label at the current instruction of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Label +** Label to define. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddLabel( + IN gcSHADER Shader, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddSource +******************************************************************************** +** +** Add a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSource( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceIndexed +******************************************************************************** +** +** Add a dynamically indexed source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_INDEXED Mode +** Addressing mode for the index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceIndexed( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttribute +******************************************************************************** +** +** Add an attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttribute( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttributeIndexed +******************************************************************************** +** +** Add an indexed attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttributeIndexed( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniform +******************************************************************************** +** +** Add a uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniform( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniformIndexed +******************************************************************************** +** +** Add an indexed uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniformIndexed( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +gceSTATUS +gcSHADER_AddSourceSamplerIndexed( + IN gcSHADER Shader, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +/******************************************************************************* +** gcSHADER_AddSourceConstant +******************************************************************************** +** +** Add a constant floating pointer value as a source operand to a gcSHADER +** object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctFLOAT Constant +** Floating pointer constant. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceConstant( + IN gcSHADER Shader, + IN gctFLOAT Constant + ); + +/******************************************************************************* +** gcSHADER_Pack +******************************************************************************** +** +** Pack a dynamically created gcSHADER object by trimming the allocated arrays +** and resolving all the labeling. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Pack( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_SetOptimizationOption +******************************************************************************** +** +** Set optimization option of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT OptimizationOption +** Optimization option. Can be one of the following: +** +** 0 - No optimization. +** 1 - Full optimization. +** Other value - For optimizer testing. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_SetOptimizationOption( + IN gcSHADER Shader, + IN gctUINT OptimizationOption + ); + +/******************************************************************************* +** gcSHADER_ReallocateFunctions +** +** Reallocate an array of pointers to gcFUNCTION objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateFunctions( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +gceSTATUS +gcSHADER_AddFunction( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + OUT gcFUNCTION * Function + ); + +gceSTATUS +gcSHADER_BeginFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +gceSTATUS +gcSHADER_EndFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +/******************************************************************************* +** gcATTRIBUTE_GetType +******************************************************************************** +** +** Get the type and array length of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the attribute. 'Type' +** can be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** attribute was declared as an array. If the attribute was not +** declared as an array, the array length will be 1. 'ArrayLength' can +** be gcvNULL, in which case no array length will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetType( + IN gcATTRIBUTE Attribute, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcATTRIBUTE_GetName +******************************************************************************** +** +** Get the name of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the attribute name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the attribute name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetName( + IN gcATTRIBUTE Attribute, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcATTRIBUTE_IsEnabled +******************************************************************************** +** +** Query the enabled state of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctBOOL * Enabled +** Pointer to a variable receiving the enabled state of the attribute. +*/ +gceSTATUS +gcATTRIBUTE_IsEnabled( + IN gcATTRIBUTE Attribute, + OUT gctBOOL * Enabled + ); + +/******************************************************************************* +** gcUNIFORM_GetType +******************************************************************************** +** +** Get the type and array length of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the uniform. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** uniform was declared as an array. If the uniform was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcUNIFORM_GetType( + IN gcUNIFORM Uniform, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcUNIFORM_GetName +******************************************************************************** +** +** Get the name of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the uniform name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the uniform name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcUNIFORM_GetName( + IN gcUNIFORM Uniform, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcUNIFORM_GetSampler +******************************************************************************** +** +** Get the physical sampler number for a sampler gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctUINT32 * Sampler +** Pointer to a variable receiving the physical sampler. +*/ +gceSTATUS +gcUNIFORM_GetSampler( + IN gcUNIFORM Uniform, + OUT gctUINT32 * Sampler + ); + +/******************************************************************************* +** gcUNIFORM_SetValue +******************************************************************************** +** +** Set the value of a uniform in integer. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctINT * Value +** Pointer to a buffer holding the integer values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValue( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueX +******************************************************************************** +** +** Set the value of a uniform in fixed point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFIXED_POINT * Value +** Pointer to a buffer holding the fixed point values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueX( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN gctFIXED_POINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueF +******************************************************************************** +** +** Set the value of a uniform in floating point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFLOAT * Value +** Pointer to a buffer holding the floating point values for the +** uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueF( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctFLOAT * Value + ); + +/******************************************************************************* +** gcOUTPUT_GetType +******************************************************************************** +** +** Get the type and array length of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the output. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** output was declared as an array. If the output was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcOUTPUT_GetType( + IN gcOUTPUT Output, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcOUTPUT_GetIndex +******************************************************************************** +** +** Get the index of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctUINT * Index +** Pointer to a variable receiving the temporary register index of the +** output. 'Index' can be gcvNULL,. in which case no index will be +** returned. +*/ +gceSTATUS +gcOUTPUT_GetIndex( + IN gcOUTPUT Output, + OUT gctUINT * Index + ); + +/******************************************************************************* +** gcOUTPUT_GetName +******************************************************************************** +** +** Get the name of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the output name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the output name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcOUTPUT_GetName( + IN gcOUTPUT Output, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +*********************************************************** F U N C T I O N S ** +*******************************************************************************/ + +/******************************************************************************* +** gcFUNCTION_ReallocateArguments +** +** Reallocate an array of gcsFUNCTION_ARGUMENT objects. +** +** INPUT: +** +** gcFUNCTION Function +** Pointer to a gcFUNCTION object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcFUNCTION_ReallocateArguments( + IN gcFUNCTION Function, + IN gctSIZE_T Count + ); + +gceSTATUS +gcFUNCTION_AddArgument( + IN gcFUNCTION Function, + IN gctUINT16 TempIndex, + IN gctUINT8 Enable, + IN gctUINT8 Qualifier + ); + +gceSTATUS +gcFUNCTION_GetArgument( + IN gcFUNCTION Function, + IN gctUINT16 Index, + OUT gctUINT16_PTR Temp, + OUT gctUINT8_PTR Enable, + OUT gctUINT8_PTR Swizzle + ); + +gceSTATUS +gcFUNCTION_GetLabel( + IN gcFUNCTION Function, + OUT gctUINT_PTR Label + ); + +/******************************************************************************* +** gcCompileShader +******************************************************************************** +** +** Compile a shader. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Shader type to compile. Can be one of the following values: +** +** gcSHADER_TYPE_VERTEX +** Compile a vertex shader. +** +** gcSHADER_TYPE_FRAGMENT +** Compile a fragment shader. +** +** gctSIZE_T SourceSize +** Size of the source buffer in bytes. +** +** gctCONST_STRING Source +** Pointer to the buffer containing the shader source code. +** +** OUTPUT: +** +** gcSHADER * Binary +** Pointer to a variable receiving the pointer to a gcSHADER object +** containg the compiled shader code. +** +** gctSTRING * Log +** Pointer to a variable receiving a string pointer containging the +** compile log. +*/ +gceSTATUS +gcCompileShader( + IN gcoHAL Hal, + IN gctINT ShaderType, + IN gctSIZE_T SourceSize, + IN gctCONST_STRING Source, + OUT gcSHADER * Binary, + OUT gctSTRING * Log + ); + +/******************************************************************************* +** gcOptimizeShader +******************************************************************************** +** +** Optimize a shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object holding information about the compiled +** shader. +** +** gctFILE LogFile +** Pointer to an open FILE object. +*/ +gceSTATUS +gcOptimizeShader( + IN gcSHADER Shader, + IN gctFILE LogFile + ); + +/******************************************************************************* +** gcLinkShaders +******************************************************************************** +** +** Link two shaders and generate a harwdare specific state buffer by compiling +** the compiler generated code through the resource allocator and code +** generator. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to a gcSHADER object holding information about the compiled +** vertex shader. +** +** gcSHADER FragmentShader +** Pointer to a gcSHADER object holding information about the compiled +** fragment shader. +** +** gceSHADER_FLAGS Flags +** Compiler flags. Can be any of the following: +** +** gcvSHADER_DEAD_CODE - Dead code elimination. +** gcvSHADER_RESOURCE_USAGE - Resource usage optimizaion. +** gcvSHADER_OPTIMIZER - Full optimization. +** gcvSHADER_USE_GL_Z - Use OpenGL ES Z coordinate. +** gcvSHADER_USE_GL_POSITION - Use OpenGL ES gl_Position. +** gcvSHADER_USE_GL_FACE - Use OpenGL ES gl_FaceForward. +** +** OUTPUT: +** +** gctSIZE_T * StateBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'StateBuffer'. +** +** gctPOINTER * StateBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLinkShaders( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gceSHADER_FLAGS Flags, + OUT gctSIZE_T * StateBufferSize, + OUT gctPOINTER * StateBuffer, + OUT gcsHINT_PTR * Hints + ); + +/******************************************************************************* +** gcLoadShaders +******************************************************************************** +** +** Load a pre-compiled and pre-linked shader program into the hardware. +** +** INPUT: +** +** gcoHAL Hal +** Pointer to a gcoHAL object. +** +** gctSIZE_T StateBufferSize +** The number of bytes in the 'StateBuffer'. +** +** gctPOINTER StateBuffer +** Pointer to the states that make up the shader program. +** +** gcsHINT_PTR Hints +** Pointer to a gcsHINT structure that contains information required +** when loading the shader states. +** +** gcePRIMITIVE PrimitiveType +** Primitive type to be rendered. +*/ +gceSTATUS +gcLoadShaders( + IN gcoHAL Hal, + IN gctSIZE_T StateBufferSize, + IN gctPOINTER StateBuffer, + IN gcsHINT_PTR Hints, + IN gcePRIMITIVE PrimitiveType + ); + +/******************************************************************************* +** gcSaveProgram +******************************************************************************** +** +** Save pre-compiled shaders and pre-linked programs to a binary file. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to vertex shader object. +** +** gcSHADER FragmentShader +** Pointer to fragment shader object. +** +** gctSIZE_T ProgramBufferSize +** Number of bytes in 'ProgramBuffer'. +** +** gctPOINTER ProgramBuffer +** Pointer to buffer containing the program states. +** +** gcsHINT_PTR Hints +** Pointer to HINTS structure for program states. +** +** OUTPUT: +** +** gctPOINTER * Binary +** Pointer to a variable receiving the binary data to be saved. +** +** gctSIZE_T * BinarySize +** Pointer to a variable receiving the number of bytes inside 'Binary'. +*/ +gceSTATUS +gcSaveProgram( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gctSIZE_T ProgramBufferSize, + IN gctPOINTER ProgramBuffer, + IN gcsHINT_PTR Hints, + OUT gctPOINTER * Binary, + OUT gctSIZE_T * BinarySize + ); + +/******************************************************************************* +** gcLoadProgram +******************************************************************************** +** +** Load pre-compiled shaders and pre-linked programs from a binary file. +** +** INPUT: +** +** gctPOINTER Binary +** Pointer to the binary data loaded. +** +** gctSIZE_T BinarySize +** Number of bytes in 'Binary'. +** +** OUTPUT: +** +** gcSHADER * VertexShader +** Pointer to a variable receiving the vertex shader object. +** +** gcSHADER * FragmentShader +** Pointer to a variable receiving the fragment shader object. +** +** gctSIZE_T * ProgramBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'ProgramBuffer'. +** +** gctPOINTER * ProgramBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLoadProgram( + IN gctPOINTER Binary, + IN gctSIZE_T BinarySize, + OUT gcSHADER * VertexShader, + OUT gcSHADER * FragmentShader, + OUT gctSIZE_T * ProgramBufferSize, + OUT gctPOINTER * ProgramBuffer, + OUT gcsHINT_PTR * Hints + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_compiler_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_driver.h b/kernel_drivers/v2/hal/inc/gc_hal_driver.h new file mode 100644 index 0000000..7a44306 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_driver.h @@ -0,0 +1,641 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_driver_h_ +#define __gc_hal_driver_h_ + +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* I/O Control Codes ****************************** +\******************************************************************************/ + +#define gcvHAL_CLASS "galcore" +#define IOCTL_GCHAL_INTERFACE 30000 +#define IOCTL_GCHAL_KERNEL_INTERFACE 30001 +#define IOCTL_GCHAL_TERMINATE 30002 + +/******************************************************************************\ +********************************* Command Codes ******************************** +\******************************************************************************/ + +typedef enum _gceHAL_COMMAND_CODES +{ + /* Generic query. */ + gcvHAL_QUERY_VIDEO_MEMORY, + gcvHAL_QUERY_CHIP_IDENTITY, + + /* Contiguous memory. */ + gcvHAL_ALLOCATE_NON_PAGED_MEMORY, + gcvHAL_FREE_NON_PAGED_MEMORY, + gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY, + gcvHAL_FREE_CONTIGUOUS_MEMORY, + + /* Video memory allocation. */ + gcvHAL_ALLOCATE_VIDEO_MEMORY, /* Enforced alignment. */ + gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY, /* No alignment. */ + gcvHAL_FREE_VIDEO_MEMORY, + + /* Physical-to-logical mapping. */ + gcvHAL_MAP_MEMORY, + gcvHAL_UNMAP_MEMORY, + + /* Logical-to-physical mapping. */ + gcvHAL_MAP_USER_MEMORY, + gcvHAL_UNMAP_USER_MEMORY, + + /* Surface lock/unlock. */ + gcvHAL_LOCK_VIDEO_MEMORY, + gcvHAL_UNLOCK_VIDEO_MEMORY, + + /* Event queue. */ + gcvHAL_EVENT_COMMIT, + + gcvHAL_USER_SIGNAL, + gcvHAL_SIGNAL, + gcvHAL_WRITE_DATA, + + gcvHAL_COMMIT, + gcvHAL_STALL, + + gcvHAL_READ_REGISTER, + gcvHAL_WRITE_REGISTER, + + gcvHAL_GET_PROFILE_SETTING, + gcvHAL_SET_PROFILE_SETTING, + + gcvHAL_READ_ALL_PROFILE_REGISTERS, + gcvHAL_PROFILE_REGISTERS_2D, + + /* Power management. */ + gcvHAL_SET_POWER_MANAGEMENT_STATE, + gcvHAL_QUERY_POWER_MANAGEMENT_STATE, + + gcvHAL_GET_BASE_ADDRESS, + + gcvHAL_SET_IDLE, /* reserved */ + + /* Queries. */ + gcvHAL_QUERY_KERNEL_SETTINGS, + + /* Reset. */ + gcvHAL_RESET, + + /* Map physical address into handle. */ + gcvHAL_MAP_PHYSICAL, + + /* Debugger stuff. */ + gcvHAL_DEBUG, + + /* Cache stuff. */ + gcvHAL_CACHE, + +#if gcdGPU_TIMEOUT + /* Broadcast GPU stuck */ + gcvHAL_BROADCAST_GPU_STUCK, +#endif +} +gceHAL_COMMAND_CODES; + +/******************************************************************************\ +****************************** Interface Structure ***************************** +\******************************************************************************/ + +#define gcdMAX_PROFILE_FILE_NAME 128 + +typedef struct _gcsHAL_INTERFACE +{ + /* Command code. */ + gceHAL_COMMAND_CODES command; + + /* Status value. */ + gceSTATUS status; + + /* Handle to this interface channel. */ + gctHANDLE handle; + + /* Pid of the client. */ + gctUINT32 pid; + + /* Union of command structures. */ + union _u + { + /* gcvHAL_GET_BASE_ADDRESS */ + struct _gcsHAL_GET_BASE_ADDRESS + { + /* Physical memory address of internal memory. */ + OUT gctUINT32 baseAddress; + } + GetBaseAddress; + + /* gcvHAL_QUERY_VIDEO_MEMORY */ + struct _gcsHAL_QUERY_VIDEO_MEMORY + { + /* Physical memory address of internal memory. */ + OUT gctPHYS_ADDR internalPhysical; + + /* Size in bytes of internal memory.*/ + OUT gctSIZE_T internalSize; + + /* Physical memory address of external memory. */ + OUT gctPHYS_ADDR externalPhysical; + + /* Size in bytes of external memory.*/ + OUT gctSIZE_T externalSize; + + /* Physical memory address of contiguous memory. */ + OUT gctPHYS_ADDR contiguousPhysical; + + /* Size in bytes of contiguous memory.*/ + OUT gctSIZE_T contiguousSize; + } + QueryVideoMemory; + + /* gcvHAL_QUERY_CHIP_IDENTITY */ + struct _gcsHAL_QUERY_CHIP_IDENTITY + { + + /* Chip model. */ + OUT gceCHIPMODEL chipModel; + + /* Revision value.*/ + OUT gctUINT32 chipRevision; + + /* Supported feature fields. */ + OUT gctUINT32 chipFeatures; + + /* Supported minor feature fields. */ + OUT gctUINT32 chipMinorFeatures; + + /* Supported minor feature 1 fields. */ + OUT gctUINT32 chipMinorFeatures1; + + /* Supported minor feature 2 fields. */ + OUT gctUINT32 chipMinorFeatures2; + + /* Number of streams supported. */ + OUT gctUINT32 streamCount; + + /* Total number of temporary registers per thread. */ + OUT gctUINT32 registerMax; + + /* Maximum number of threads. */ + OUT gctUINT32 threadCount; + + /* Number of shader cores. */ + OUT gctUINT32 shaderCoreCount; + + /* Size of the vertex cache. */ + OUT gctUINT32 vertexCacheSize; + + /* Number of entries in the vertex output buffer. */ + OUT gctUINT32 vertexOutputBufferSize; + } + QueryChipIdentity; + + /* gcvHAL_MAP_MEMORY */ + struct _gcsHAL_MAP_MEMORY + { + /* Physical memory address to map. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to map. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory. */ + OUT gctPOINTER logical; + } + MapMemory; + + /* gcvHAL_UNMAP_MEMORY */ + struct _gcsHAL_UNMAP_MEMORY + { + /* Physical memory address to unmap. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to unmap. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory to unmap. */ + IN gctPOINTER logical; + } + UnmapMemory; + + /* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctUINT bytes; + + /* Buffer alignment. */ + IN gctUINT alignment; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateLinearVideoMemory; + + /* gcvHAL_ALLOCATE_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_VIDEO_MEMORY + { + /* Width of rectangle to allocate. */ + IN OUT gctUINT width; + + /* Height of rectangle to allocate. */ + IN OUT gctUINT height; + + /* Depth of rectangle to allocate. */ + IN gctUINT depth; + + /* Format rectangle to allocate in gceSURF_FORMAT. */ + IN gceSURF_FORMAT format; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateVideoMemory; + + /* gcvHAL_FREE_VIDEO_MEMORY */ + struct _gcsHAL_FREE_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + +#ifdef __QNXNTO__ +/* TODO: This is part of the unlock - why is it here? */ + /* Mapped logical address to unmap in user space. */ + OUT gctPOINTER memory; + + /* Number of bytes to allocated. */ + OUT gctSIZE_T bytes; +#endif + } + FreeVideoMemory; + + /* gcvHAL_LOCK_VIDEO_MEMORY */ + struct _gcsHAL_LOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Hardware specific address. */ + OUT gctUINT32 address; + + /* Mapped logical address. */ + OUT gctPOINTER memory; + } + LockVideoMemory; + + /* gcvHAL_UNLOCK_VIDEO_MEMORY */ + struct _gcsHAL_UNLOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Type of surface. */ + IN gceSURF_TYPE type; + + /* Flag to unlock surface asynchroneously. */ + IN OUT gctBOOL asynchroneous; + } + UnlockVideoMemory; + + /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */ + struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + } + AllocateNonPagedMemory; + + /* gcvHAL_FREE_NON_PAGED_MEMORY */ + struct _gcsHAL_FREE_NON_PAGED_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeNonPagedMemory; + + /* gcvHAL_EVENT_COMMIT. */ + struct _gcsHAL_EVENT_COMMIT + { + /* Event queue. */ + IN struct _gcsQUEUE * queue; + } + Event; + + /* gcvHAL_COMMIT */ + struct _gcsHAL_COMMIT + { + /* Command buffer. */ + IN gcoCMDBUF commandBuffer; + + /* Context buffer. */ + IN gcoCONTEXT contextBuffer; + + /* Process handle. */ + IN gctHANDLE process; + } + Commit; + + /* gcvHAL_MAP_USER_MEMORY */ + struct _gcsHAL_MAP_USER_MEMORY + { + /* Base address of user memory to map. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to map. */ + IN gctSIZE_T size; + + /* Info record required by gcvHAL_UNMAP_USER_MEMORY. */ + OUT gctPOINTER info; + + /* Physical address of mapped memory. */ + OUT gctUINT32 address; + } + MapUserMemory; + + /* gcvHAL_UNMAP_USER_MEMORY */ + struct _gcsHAL_UNMAP_USER_MEMORY + { + /* Base address of user memory to unmap. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to unmap. */ + IN gctSIZE_T size; + + /* Info record returned by gcvHAL_MAP_USER_MEMORY. */ + IN gctPOINTER info; + + /* Physical address of mapped memory as returned by + gcvHAL_MAP_USER_MEMORY. */ + IN gctUINT32 address; + } + UnmapUserMemory; + +#if !USE_NEW_LINUX_SIGNAL + /* gcsHAL_USER_SIGNAL */ + struct _gcsHAL_USER_SIGNAL + { + /* Command. */ + gceUSER_SIGNAL_COMMAND_CODES command; + + /* Signal ID. */ + IN OUT gctINT id; + + /* Reset mode. */ + IN gctBOOL manualReset; + + /* Wait timedout. */ + IN gctUINT32 wait; + + /* State. */ + IN gctBOOL state; + } + UserSignal; +#endif + + /* gcvHAL_SIGNAL. */ + struct _gcsHAL_SIGNAL + { + /* Signal handle to signal. */ + IN gctSIGNAL signal; + + /* Reserved. */ + IN gctSIGNAL auxSignal; + + /* Process owning the signal. */ + IN gctHANDLE process; + +#if defined(__QNXNTO__) + /* Client pulse side-channel connection ID. Set by client in gcoOS_CreateSignal. */ + IN gctINT32 coid; + + /* Set by server. */ + IN gctINT32 rcvid; +#endif + /* Event generated from where of pipeline */ + IN gceKERNEL_WHERE fromWhere; + } + Signal; + + /* gcvHAL_WRITE_DATA. */ + struct _gcsHAL_WRITE_DATA + { + /* Address to write data to. */ + IN gctUINT32 address; + + /* Data to write. */ + IN gctUINT32 data; + } + WriteData; + + /* gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_ALLOCATE_CONTIGUOUS_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + + } + AllocateContiguousMemory; + + /* gcvHAL_FREE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_FREE_CONTIGUOUS_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeContiguousMemory; + + /* gcvHAL_READ_REGISTER */ + struct _gcsHAL_READ_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + OUT gctUINT32 data; + } + ReadRegisterData; + + /* gcvHAL_WRITE_REGISTER */ + struct _gcsHAL_WRITE_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + IN gctUINT32 data; + } + WriteRegisterData; + + /* gcvHAL_GET_PROFILE_SETTING */ + struct _gcsHAL_GET_PROFILE_SETTING + { + /* Enable profiling */ + OUT gctBOOL enable; + + /* The profile file name */ + OUT gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + GetProfileSetting; + + /* gcvHAL_SET_PROFILE_SETTING */ + struct _gcsHAL_SET_PROFILE_SETTING + { + /* Enable profiling */ + IN gctBOOL enable; + + /* The profile file name */ + IN gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + SetProfileSetting; + + /* gcvHAL_READ_ALL_PROFILE_REGISTERS */ + struct _gcsHAL_READ_ALL_PROFILE_REGISTERS + { + /* Data read. */ + OUT gcsPROFILER_COUNTERS counters; + } + RegisterProfileData; + + /* gcvHAL_PROFILE_REGISTERS_2D */ + struct _gcsHAL_PROFILE_REGISTERS_2D + { + /* Data read. */ + OUT gcs2D_PROFILE_PTR hwProfile2D; + } + RegisterProfileData2D; + + /* Power management. */ + /* gcvHAL_SET_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_SET_POWER_MANAGEMENT + { + /* Data read. */ + IN gceCHIPPOWERSTATE state; + } + SetPowerManagement; + + /* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_QUERY_POWER_MANAGEMENT + { + /* Data read. */ + OUT gceCHIPPOWERSTATE state; + + /* Idle query. */ + OUT gctBOOL isIdle; + } + QueryPowerManagement; + + /* gcvHAL_QUERY_KERNEL_SETTINGS */ + struct _gcsHAL_QUERY_KERNEL_SETTINGS + { + /* Settings.*/ + OUT gcsKERNEL_SETTINGS settings; + } + QueryKernelSettings; + + /* gcvHAL_MAP_PHYSICAL */ + struct _gcsHAL_MAP_PHYSICAL + { + /* gcvTRUE to map, gcvFALSE to unmap. */ + IN gctBOOL map; + + /* Physical address. */ + IN OUT gctPHYS_ADDR physical; + } + MapPhysical; + + /* gcvHAL_DEBUG */ + struct _gcsHAL_DEBUG + { + /* If gcvTRUE, set the debug information. */ + IN gctBOOL set; + IN gctUINT32 level; + IN gctUINT32 zones; + IN gctBOOL enable; + + /* Message to print if not empty. */ + IN gctCHAR message[80]; + } + Debug; + + struct _gcsHAL_CACHE + { + IN gctBOOL invalidate; + IN gctHANDLE process; + IN gctPOINTER logical; + IN gctSIZE_T bytes; + } + Cache; + } + u; +} +gcsHAL_INTERFACE; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_driver_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_dump.h b/kernel_drivers/v2/hal/inc/gc_hal_dump.h new file mode 100644 index 0000000..570218c --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_dump.h @@ -0,0 +1,90 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_dump_h_ +#define __gc_hal_dump_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** FILE LAYOUT: +** +** gcsDUMP_FILE structure +** +** gcsDUMP_DATA frame +** gcsDUMP_DATA or gcDUMP_DATA_SIZE records rendingring the frame +** gctUINT8 data[length] +*/ + +#define gcvDUMP_FILE_SIGNATURE gcmCC('g','c','D','B') + +typedef struct _gcsDUMP_FILE +{ + gctUINT32 signature; /* File signature */ + gctSIZE_T length; /* Length of file */ + gctUINT32 frames; /* Number of frames in file */ +} +gcsDUMP_FILE; + +typedef enum _gceDUMP_TAG +{ + gcvTAG_SURFACE = gcmCC('s','u','r','f'), + gcvTAG_FRAME = gcmCC('f','r','m',' '), + gcvTAG_COMMAND = gcmCC('c','m','d',' '), + gcvTAG_INDEX = gcmCC('i','n','d','x'), + gcvTAG_STREAM = gcmCC('s','t','r','m'), + gcvTAG_TEXTURE = gcmCC('t','e','x','t'), + gcvTAG_RENDER_TARGET = gcmCC('r','n','d','r'), + gcvTAG_DEPTH = gcmCC('z','b','u','f'), + gcvTAG_RESOLVE = gcmCC('r','s','l','v'), + gcvTAG_DELETE = gcmCC('d','e','l',' '), +} +gceDUMP_TAG; + +typedef struct _gcsDUMP_SURFACE +{ + gceDUMP_TAG type; /* Type of record. */ + gctUINT32 address; /* Address of the surface. */ + gctINT16 width; /* Width of surface. */ + gctINT16 height; /* Height of surface. */ + gceSURF_FORMAT format; /* Surface pixel format. */ + gctSIZE_T length; /* Number of bytes inside the surface. */ +} +gcsDUMP_SURFACE; + +typedef struct _gcsDUMP_DATA +{ + gceDUMP_TAG type; /* Type of record. */ + gctSIZE_T length; /* Number of bytes of data. */ + gctUINT32 address; /* Address for the data. */ +} +gcsDUMP_DATA; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_dump_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_engine.h b/kernel_drivers/v2/hal/inc/gc_hal_engine.h new file mode 100644 index 0000000..0382081 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_engine.h @@ -0,0 +1,1597 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_engine_h_ +#define __gc_hal_engine_h_ + +#include "gc_hal_types.h" +#include "gc_hal_enum.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoSTREAM * gcoSTREAM; +typedef struct _gcoVERTEX * gcoVERTEX; +typedef struct _gcoTEXTURE * gcoTEXTURE; +typedef struct _gcoINDEX * gcoINDEX; +typedef struct _gcsVERTEX_ATTRIBUTES * gcsVERTEX_ATTRIBUTES_PTR; + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +/* Shading format. */ +typedef enum _gceSHADING +{ + gcvSHADING_SMOOTH, + gcvSHADING_FLAT_D3D, + gcvSHADING_FLAT_OPENGL, +} +gceSHADING; + +/* Culling modes. */ +typedef enum _gceCULL +{ + gcvCULL_NONE, + gcvCULL_CCW, + gcvCULL_CW, +} +gceCULL; + +/* Fill modes. */ +typedef enum _gceFILL +{ + gcvFILL_POINT, + gcvFILL_WIRE_FRAME, + gcvFILL_SOLID, +} +gceFILL; + +/* Compare modes. */ +typedef enum _gceCOMPARE +{ + gcvCOMPARE_NEVER, + gcvCOMPARE_NOT_EQUAL, + gcvCOMPARE_LESS, + gcvCOMPARE_LESS_OR_EQUAL, + gcvCOMPARE_EQUAL, + gcvCOMPARE_GREATER, + gcvCOMPARE_GREATER_OR_EQUAL, + gcvCOMPARE_ALWAYS, +} +gceCOMPARE; + +/* Stencil modes. */ +typedef enum _gceSTENCIL_MODE +{ + gcvSTENCIL_NONE, + gcvSTENCIL_SINGLE_SIDED, + gcvSTENCIL_DOUBLE_SIDED, +} +gceSTENCIL_MODE; + +/* Stencil operations. */ +typedef enum _gceSTENCIL_OPERATION +{ + gcvSTENCIL_KEEP, + gcvSTENCIL_REPLACE, + gcvSTENCIL_ZERO, + gcvSTENCIL_INVERT, + gcvSTENCIL_INCREMENT, + gcvSTENCIL_DECREMENT, + gcvSTENCIL_INCREMENT_SATURATE, + gcvSTENCIL_DECREMENT_SATURATE, +} +gceSTENCIL_OPERATION; + +/* Stencil selection. */ +typedef enum _gceSTENCIL_WHERE +{ + gcvSTENCIL_FRONT, + gcvSTENCIL_BACK, +} +gceSTENCIL_WHERE; + +/* Texture addressing selection. */ +typedef enum _gceTEXTURE_WHICH +{ + gcvTEXTURE_S, + gcvTEXTURE_T, + gcvTEXTURE_R, +} +gceTEXTURE_WHICH; + +/* Texture addressing modes. */ +typedef enum _gceTEXTURE_ADDRESSING +{ + gcvTEXTURE_WRAP, + gcvTEXTURE_CLAMP, + gcvTEXTURE_BORDER, + gcvTEXTURE_MIRROR, + gcvTEXTURE_MIRROR_ONCE, +} +gceTEXTURE_ADDRESSING; + +/* Texture filters. */ +typedef enum _gceTEXTURE_FILTER +{ + gcvTEXTURE_NONE, + gcvTEXTURE_POINT, + gcvTEXTURE_LINEAR, + gcvTEXTURE_ANISOTROPIC, +} +gceTEXTURE_FILTER; + +/* Primitive types. */ +typedef enum _gcePRIMITIVE +{ + gcvPRIMITIVE_POINT_LIST, + gcvPRIMITIVE_LINE_LIST, + gcvPRIMITIVE_LINE_STRIP, + gcvPRIMITIVE_LINE_LOOP, + gcvPRIMITIVE_TRIANGLE_LIST, + gcvPRIMITIVE_TRIANGLE_STRIP, + gcvPRIMITIVE_TRIANGLE_FAN, +} +gcePRIMITIVE; + +/* Index types. */ +typedef enum _gceINDEX_TYPE +{ + gcvINDEX_8, + gcvINDEX_16, + gcvINDEX_32, +} +gceINDEX_TYPE; + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Query the target capabilities. */ +gceSTATUS +gcoHAL_QueryTargetCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MultiTargetCount, + OUT gctUINT * MaxSamples + ); + +gceSTATUS +gcoHAL_SetDepthOnly( + IN gcoHAL Hal, + IN gctBOOL Enable + ); + +gceSTATUS +gcoHAL_QueryShaderCaps( + IN gcoHAL Hal, + OUT gctUINT * VertexUniforms, + OUT gctUINT * FragmentUniforms, + OUT gctUINT * Varyings + ); + +gceSTATUS +gcoHAL_QueryTextureCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoHAL_QueryStreamCaps( + IN gcoHAL Hal, + OUT gctUINT32 * MaxAttributes, + OUT gctUINT32 * MaxStreamSize, + OUT gctUINT32 * NumberOfStreams, + OUT gctUINT32 * Alignment + ); + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*--------------------------------- gcoSURF 3D --------------------------------*/ + +/* Copy surface. */ +gceSTATUS +gcoSURF_Copy( + IN gcoSURF Surface, + IN gcoSURF Source + ); + +/* Clear surface. */ +gceSTATUS +gcoSURF_Clear( + IN gcoSURF Surface, + IN gctUINT Flags + ); + +/* Set number of samples for a gcoSURF object. */ +gceSTATUS +gcoSURF_SetSamples( + IN gcoSURF Surface, + IN gctUINT Samples + ); + +/* Get the number of samples per pixel. */ +gceSTATUS +gcoSURF_GetSamples( + IN gcoSURF Surface, + OUT gctUINT_PTR Samples + ); + +/* Clear rectangular surface. */ +gceSTATUS +gcoSURF_ClearRect( + IN gcoSURF Surface, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + IN gctUINT Flags + ); + +/* TO BE REMOVED */ +#if 1 + gceSTATUS + depr_gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight + ); + + gceSTATUS + depr_gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); +#endif + +/* Resample surface. */ +gceSTATUS +gcoSURF_Resample( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Resolve surface. */ +gceSTATUS +gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Resolve rectangular area of a surface. */ +gceSTATUS +gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); + +/* Set surface resolvability. */ +gceSTATUS +gcoSURF_SetResolvability( + IN gcoSURF Surface, + IN gctBOOL Resolvable + ); + +/******************************************************************************\ +******************************** gcoINDEX Object ******************************* +\******************************************************************************/ + +/* Construct a new gcoINDEX object. */ +gceSTATUS +gcoINDEX_Construct( + IN gcoHAL Hal, + OUT gcoINDEX * Index + ); + +/* Destroy a gcoINDEX object. */ +gceSTATUS +gcoINDEX_Destroy( + IN gcoINDEX Index + ); + +/* Lock index in memory. */ +gceSTATUS +gcoINDEX_Lock( + IN gcoINDEX Index, + OUT gctUINT32 * Address, + OUT gctPOINTER * Memory + ); + +/* Unlock index that was previously locked with gcoINDEX_Lock. */ +gceSTATUS +gcoINDEX_Unlock( + IN gcoINDEX Index + ); + +/* Upload index data into the memory. */ +gceSTATUS +gcoINDEX_Load( + IN gcoINDEX Index, + IN gceINDEX_TYPE IndexType, + IN gctUINT32 IndexCount, + IN gctPOINTER IndexBuffer + ); + +/* Bind an index object to the hardware, for neocore hacking*/ +gceSTATUS +gcoINDEX_LoadHack( + IN gcoINDEX Index, + IN gceINDEX_TYPE IndexType, + IN gctUINT32 IndexCount, + IN gctPOINTER IndexBuffer + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_Bind( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_BindOffset( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset + ); + +/* Free existing index buffer. */ +gceSTATUS +gcoINDEX_Free( + IN gcoINDEX Index + ); + +/* Upload data into an index buffer. */ +gceSTATUS +gcoINDEX_Upload( + IN gcoINDEX Index, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Upload data into an index buffer starting at an offset. */ +gceSTATUS +gcoINDEX_UploadOffset( + IN gcoINDEX Index, + IN gctUINT32 Offset, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Query the index capabilities. */ +gceSTATUS +gcoINDEX_QueryCaps( + OUT gctBOOL * Index8, + OUT gctBOOL * Index16, + OUT gctBOOL * Index32, + OUT gctUINT * MaxIndex + ); + +/* Determine the index range in the current index buffer. */ +gceSTATUS +gcoINDEX_GetIndexRange( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset, + IN gctUINT32 Count, + OUT gctUINT32 * MinimumIndex, + OUT gctUINT32 * MaximumIndex + ); + +/* Dynamic buffer management. */ +gceSTATUS +gcoINDEX_SetDynamic( + IN gcoINDEX Index, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +gceSTATUS +gcoINDEX_UploadDynamic( + IN gcoINDEX Index, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes + ); + +/******************************************************************************\ +********************************** gco3D Object ********************************* +\******************************************************************************/ + +/* Clear flags. */ +typedef enum _gceCLEAR +{ + gcvCLEAR_COLOR = 0x1, + gcvCLEAR_DEPTH = 0x2, + gcvCLEAR_STENCIL = 0x4, + gcvCLEAR_HZ = 0x8, + gcvCLEAR_HAS_VAA = 0x10, +} +gceCLEAR; + +/* Blending targets. */ +typedef enum _gceBLEND_UNIT +{ + gcvBLEND_SOURCE, + gcvBLEND_TARGET, +} +gceBLEND_UNIT; + +/* Construct a new gco3D object. */ +gceSTATUS +gco3D_Construct( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +/* Destroy an gco3D object. */ +gceSTATUS +gco3D_Destroy( + IN gco3D Engine + ); + +/* Set 3D API type. */ +gceSTATUS +gco3D_SetAPI( + IN gco3D Engine, + IN gceAPI ApiType + ); + +/* Set render target. */ +gceSTATUS +gco3D_SetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset render target. */ +gceSTATUS +gco3D_UnsetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set depth buffer. */ +gceSTATUS +gco3D_SetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset depth buffer. */ +gceSTATUS +gco3D_UnsetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set viewport. */ +gceSTATUS +gco3D_SetViewport( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set scissors. */ +gceSTATUS +gco3D_SetScissors( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set clear color. */ +gceSTATUS +gco3D_SetClearColor( + IN gco3D Engine, + IN gctUINT8 Red, + IN gctUINT8 Green, + IN gctUINT8 Blue, + IN gctUINT8 Alpha + ); + +/* Set fixed point clear color. */ +gceSTATUS +gco3D_SetClearColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point clear color. */ +gceSTATUS +gco3D_SetClearColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set fixed point clear depth. */ +gceSTATUS +gco3D_SetClearDepthX( + IN gco3D Engine, + IN gctFIXED_POINT Depth + ); + +/* Set floating point clear depth. */ +gceSTATUS +gco3D_SetClearDepthF( + IN gco3D Engine, + IN gctFLOAT Depth + ); + +/* Set clear stencil. */ +gceSTATUS +gco3D_SetClearStencil( + IN gco3D Engine, + IN gctUINT32 Stencil + ); + +/* Clear a Rect sub-surface. */ +gceSTATUS +gco3D_ClearRect( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctPOINTER Memory, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + +/* Clear surface. */ +gceSTATUS +gco3D_Clear( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + + +/* Clear tile status. */ +gceSTATUS +gco3D_ClearTileStatus( + IN gco3D Engine, + IN gcsSURF_INFO_PTR Surface, + IN gctUINT32 TileStatusAddress, + IN gctUINT32 Flags + ); + +/* Set shading mode. */ +gceSTATUS +gco3D_SetShading( + IN gco3D Engine, + IN gceSHADING Shading + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_EnableBlending( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set blending function. */ +gceSTATUS +gco3D_SetBlendFunction( + IN gco3D Engine, + IN gceBLEND_UNIT Unit, + IN gceBLEND_FUNCTION FunctionRGB, + IN gceBLEND_FUNCTION FunctionAlpha + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_SetBlendMode( + IN gco3D Engine, + IN gceBLEND_MODE ModeRGB, + IN gceBLEND_MODE ModeAlpha + ); + +/* Set blending color. */ +gceSTATUS +gco3D_SetBlendColor( + IN gco3D Engine, + IN gctUINT Red, + IN gctUINT Green, + IN gctUINT Blue, + IN gctUINT Alpha + ); + +/* Set fixed point blending color. */ +gceSTATUS +gco3D_SetBlendColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point blending color. */ +gceSTATUS +gco3D_SetBlendColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set culling mode. */ +gceSTATUS +gco3D_SetCulling( + IN gco3D Engine, + IN gceCULL Mode + ); + +/* Enable point size */ +gceSTATUS +gco3D_SetPointSizeEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set point sprite */ +gceSTATUS +gco3D_SetPointSprite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set fill mode. */ +gceSTATUS +gco3D_SetFill( + IN gco3D Engine, + IN gceFILL Mode + ); + +/* Set depth compare mode. */ +gceSTATUS +gco3D_SetDepthCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Enable depth writing. */ +gceSTATUS +gco3D_EnableDepthWrite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth mode. */ +gceSTATUS +gco3D_SetDepthMode( + IN gco3D Engine, + IN gceDEPTH_MODE Mode + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeX( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFIXED_POINT Near, + IN gctFIXED_POINT Far + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeF( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFLOAT Near, + IN gctFLOAT Far + ); + +/* Set last pixel enable */ +gceSTATUS +gco3D_SetLastPixelEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth Bias and Scale */ +gceSTATUS +gco3D_SetDepthScaleBiasX( + IN gco3D Engine, + IN gctFIXED_POINT DepthScale, + IN gctFIXED_POINT DepthBias + ); + +gceSTATUS +gco3D_SetDepthScaleBiasF( + IN gco3D Engine, + IN gctFLOAT DepthScale, + IN gctFLOAT DepthBias + ); + +/* Enable or disable dithering. */ +gceSTATUS +gco3D_EnableDither( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set color write enable bits. */ +gceSTATUS +gco3D_SetColorWrite( + IN gco3D Engine, + IN gctUINT8 Enable + ); + +/* Enable or disable early depth. */ +gceSTATUS +gco3D_SetEarlyDepth( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Enable or disable depth-only mode. */ +gceSTATUS +gco3D_SetDepthOnly( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set stencil mode. */ +gceSTATUS +gco3D_SetStencilMode( + IN gco3D Engine, + IN gceSTENCIL_MODE Mode + ); + +/* Set stencil mask. */ +gceSTATUS +gco3D_SetStencilMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil write mask. */ +gceSTATUS +gco3D_SetStencilWriteMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil reference. */ +gceSTATUS +gco3D_SetStencilReference( + IN gco3D Engine, + IN gctUINT8 Reference, + IN gctBOOL Front + ); + +/* Set stencil compare. */ +gceSTATUS +gco3D_SetStencilCompare( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceCOMPARE Compare + ); + +/* Set stencil operation on pass. */ +gceSTATUS +gco3D_SetStencilPass( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on fail. */ +gceSTATUS +gco3D_SetStencilFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on depth fail. */ +gceSTATUS +gco3D_SetStencilDepthFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Enable or disable alpha test. */ +gceSTATUS +gco3D_SetAlphaTest( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set alpha test compare. */ +gceSTATUS +gco3D_SetAlphaCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Set alpha test reference in unsigned integer. */ +gceSTATUS +gco3D_SetAlphaReference( + IN gco3D Engine, + IN gctUINT8 Reference + ); + +/* Set alpha test reference in fixed point. */ +gceSTATUS +gco3D_SetAlphaReferenceX( + IN gco3D Engine, + IN gctFIXED_POINT Reference + ); + +/* Set alpha test reference in floating point. */ +gceSTATUS +gco3D_SetAlphaReferenceF( + IN gco3D Engine, + IN gctFLOAT Reference + ); + +/* Enable/Disable anti-alias line. */ +gceSTATUS +gco3D_SetAntiAliasLine( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set texture slot for anti-alias line. */ +gceSTATUS +gco3D_SetAALineTexSlot( + IN gco3D Engine, + IN gctUINT TexSlot + ); + +/* Set anti-alias line width scale. */ +gceSTATUS +gco3D_SetAALineWidth( + IN gco3D Engine, + IN gctFLOAT Width + ); + +/* Draw a number of primitives. */ +gceSTATUS +gco3D_DrawPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT StartVertex, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of primitives using offsets. */ +gceSTATUS +gco3D_DrawPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives. */ +gceSTATUS +gco3D_DrawIndexedPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT BaseVertex, + IN gctINT StartIndex, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives using offsets. */ +gceSTATUS +gco3D_DrawIndexedPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 BaseOffset, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Enable or disable anti-aliasing. */ +gceSTATUS +gco3D_SetAntiAlias( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Write data into the command buffer. */ +gceSTATUS +gco3D_WriteBuffer( + IN gco3D Engine, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes, + IN gctBOOL Aligned + ); + +/*Send sempahore and stall until sempahore is signalled.*/ +gceSTATUS +gco3D_Semaphore( + IN gco3D Engine, + IN gceWHERE From, + IN gceWHERE To, + IN gceHOW How); + +/*Set the subpixels center .*/ +gceSTATUS +gco3D_SetCentroids( + IN gco3D Engine, + IN gctUINT32 Index, + IN gctPOINTER Centroids + ); +/*----------------------------------------------------------------------------*/ +/*-------------------------- gco3D Fragment Processor ------------------------*/ + +/* Set the fragment processor configuration. */ +gceSTATUS +gco3D_SetFragmentConfiguration( + IN gco3D Engine, + IN gctBOOL ColorFromStream, + IN gctBOOL EnableFog, + IN gctBOOL EnableSmoothPoint, + IN gctUINT32 ClipPlanes + ); + +/* Enable/disable texture stage operation. */ +gceSTATUS +gco3D_EnableTextureStage( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL Enable + ); + +/* Program the channel enable masks for the color texture function. */ +gceSTATUS +gco3D_SetTextureColorMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the channel enable masks for the alpha texture function. */ +gceSTATUS +gco3D_SetTextureAlphaMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the constant fragment color. */ +gceSTATUS +gco3D_SetFragmentColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFragmentColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant fog color. */ +gceSTATUS +gco3D_SetFogColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFogColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant texture color. */ +gceSTATUS +gco3D_SetTetxureColorX( + IN gco3D Engine, + IN gctINT Stage, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetTetxureColorF( + IN gco3D Engine, + IN gctINT Stage, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Configure color texture function. */ +gceSTATUS +gco3D_SetColorTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + +/* Configure alpha texture function. */ +gceSTATUS +gco3D_SetAlphaTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + + +/******************************************************************************\ +******************************* gcoTEXTURE Object ******************************* +\******************************************************************************/ + +/* Cube faces. */ +typedef enum _gceTEXTURE_FACE +{ + gcvFACE_NONE, + gcvFACE_POSITIVE_X, + gcvFACE_NEGATIVE_X, + gcvFACE_POSITIVE_Y, + gcvFACE_NEGATIVE_Y, + gcvFACE_POSITIVE_Z, + gcvFACE_NEGATIVE_Z, +} +gceTEXTURE_FACE; + +typedef struct _gcsTEXTURE +{ + /* Addressing modes. */ + gceTEXTURE_ADDRESSING s; + gceTEXTURE_ADDRESSING t; + gceTEXTURE_ADDRESSING r; + + /* Border color. */ + gctUINT8 border[4]; + + /* Filters. */ + gceTEXTURE_FILTER minFilter; + gceTEXTURE_FILTER magFilter; + gceTEXTURE_FILTER mipFilter; + + /* Level of detail. */ + gctFIXED_POINT lodBias; + gctFIXED_POINT lodMin; + gctFIXED_POINT lodMax; +} +gcsTEXTURE, * gcsTEXTURE_PTR; + + +/* Construct a new gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Construct( + IN gcoHAL Hal, + OUT gcoTEXTURE * Texture + ); + +/* Construct a new sized gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_ConstructSized( + IN gcoHAL Hal, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gctUINT MipMapCount, + IN gcePOOL Pool, + OUT gcoTEXTURE * Texture + ); + +/* Destroy an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Destroy( + IN gcoTEXTURE Texture + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Upload( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadSub( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload compressed data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadCompressed( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Get gcoSURF object for a mipmap level. */ +gceSTATUS +gcoTEXTURE_GetMipMap( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + OUT gcoSURF * Surface + ); + +/* Get gcoSURF object for a mipmap level and face offset. */ +gceSTATUS +gcoTEXTURE_GetMipMapFace( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + OUT gcoSURF * Surface, + OUT gctUINT32_PTR Offset + ); + +gceSTATUS +gcoTEXTURE_AddMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromClient( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromSurface( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_SetEndianHint( + IN gcoTEXTURE Texture, + IN gceENDIAN_HINT EndianHint + ); + +gceSTATUS +gcoTEXTURE_SetAddressingMode( + IN gcoTEXTURE Texture, + IN gceTEXTURE_WHICH Which, + IN gceTEXTURE_ADDRESSING Mode + ); + +gceSTATUS +gcoTEXTURE_SetBorderColor( + IN gcoTEXTURE Texture, + IN gctUINT Red, + IN gctUINT Green, + IN gctUINT Blue, + IN gctUINT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetBorderColorX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetBorderColorF( + IN gcoTEXTURE Texture, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +gceSTATUS +gcoTEXTURE_SetMinFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetMagFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetMipFilter( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FILTER Filter + ); + +gceSTATUS +gcoTEXTURE_SetLODBiasX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT Bias + ); + +gceSTATUS +gcoTEXTURE_SetLODBiasF( + IN gcoTEXTURE Texture, + IN gctFLOAT Bias + ); + +gceSTATUS +gcoTEXTURE_SetLODMinX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMinF( + IN gcoTEXTURE Texture, + IN gctFLOAT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMaxX( + IN gcoTEXTURE Texture, + IN gctFIXED_POINT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_SetLODMaxF( + IN gcoTEXTURE Texture, + IN gctFLOAT LevelOfDetail + ); + +gceSTATUS +gcoTEXTURE_Bind( + IN gcoTEXTURE Texture, + IN gctINT Sampler + ); + +gceSTATUS +gcoTEXTURE_Disable( + IN gcoHAL Hal, + IN gctINT Sampler + ); + +gceSTATUS +gcoTEXTURE_Flush( + IN gcoTEXTURE Texture + ); + +gceSTATUS +gcoTEXTURE_QueryCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoTEXTURE_GetClosestFormat( + IN gcoHAL Hal, + IN gceSURF_FORMAT InFormat, + OUT gceSURF_FORMAT* OutFormat + ); + +gceSTATUS +gcoTEXTURE_RenderIntoMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level + ); + +gceSTATUS +gcoTEXTURE_IsRenderable( + IN gcoTEXTURE Texture, + IN gctUINT Level + ); + +gceSTATUS +gcoTEXTURE_IsComplete( + IN gcoTEXTURE Texture, + IN gctINT MaxLevel + ); + +gceSTATUS +gcoTEXTURE_BindTexture( + IN gcoTEXTURE Texture, + IN gctINT Sampler, + IN gcsTEXTURE_PTR Info + ); + +/******************************************************************************\ +******************************* gcoSTREAM Object ****************************** +\******************************************************************************/ + +typedef enum _gceVERTEX_FORMAT +{ + gcvVERTEX_BYTE, + gcvVERTEX_UNSIGNED_BYTE, + gcvVERTEX_SHORT, + gcvVERTEX_UNSIGNED_SHORT, + gcvVERTEX_INT, + gcvVERTEX_UNSIGNED_INT, + gcvVERTEX_FIXED, + gcvVERTEX_HALF, + gcvVERTEX_FLOAT, +} +gceVERTEX_FORMAT; + +gceSTATUS +gcoSTREAM_Construct( + IN gcoHAL Hal, + OUT gcoSTREAM * Stream + ); + +gceSTATUS +gcoSTREAM_Destroy( + IN gcoSTREAM Stream + ); + +gceSTATUS +gcoSTREAM_Upload( + IN gcoSTREAM Stream, + IN gctCONST_POINTER Buffer, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes, + IN gctBOOL Dynamic + ); + +gceSTATUS +gcoSTREAM_SetStride( + IN gcoSTREAM Stream, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoSTREAM_Lock( + IN gcoSTREAM Stream, + OUT gctPOINTER * Logical, + OUT gctUINT32 * Physical + ); + +gceSTATUS +gcoSTREAM_Unlock( + IN gcoSTREAM Stream); + +gceSTATUS +gcoSTREAM_Reserve( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoSTREAM_Flush( + IN gcoSTREAM Stream + ); + +/* Dynamic buffer API. */ +gceSTATUS +gcoSTREAM_SetDynamic( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +typedef struct _gcsSTREAM_INFO +{ + gctUINT index; + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT components; + gctSIZE_T size; + gctCONST_POINTER data; + gctUINT stride; +} +gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR; + +gceSTATUS +gcoSTREAM_UploadDynamic( + IN gcoSTREAM Stream, + IN gctUINT VertexCount, + IN gctUINT InfoCount, + IN gcsSTREAM_INFO_PTR Info, + IN gcoVERTEX Vertex + ); + +/******************************************************************************\ +******************************** gcoVERTEX Object ****************************** +\******************************************************************************/ + +typedef struct _gcsVERTEX_ATTRIBUTES +{ + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT32 components; + gctSIZE_T size; + gctUINT32 stream; + gctUINT32 offset; + gctUINT32 stride; +} +gcsVERTEX_ATTRIBUTES; + +gceSTATUS +gcoVERTEX_Construct( + IN gcoHAL Hal, + OUT gcoVERTEX * Vertex + ); + +gceSTATUS +gcoVERTEX_Destroy( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_Reset( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_EnableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index, + IN gceVERTEX_FORMAT Format, + IN gctBOOL Normalized, + IN gctUINT32 Components, + IN gcoSTREAM Stream, + IN gctUINT32 Offset, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoVERTEX_DisableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index + ); + +gceSTATUS +gcoVERTEX_Bind( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_BindHack( + IN gctUINT32 ActiveAttributeCount, + IN gctUINT32 TotalStride, + IN gcoVERTEX Vertex, + IN gctUINT32 Address + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_engine_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_enum.h b/kernel_drivers/v2/hal/inc/gc_hal_enum.h new file mode 100644 index 0000000..0f6ccf8 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_enum.h @@ -0,0 +1,608 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_enum_h_ +#define __gc_hal_enum_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Chip models. */ +typedef enum _gceCHIPMODEL +{ + gcv300 = 0x0300, + gcv400 = 0x0400, + gcv410 = 0x0410, + gcv450 = 0x0450, + gcv500 = 0x0500, + gcv530 = 0x0530, + gcv600 = 0x0600, + gcv700 = 0x0700, + gcv800 = 0x0800, + gcv860 = 0x0860, + gcv1000 = 0x1000, +} +gceCHIPMODEL; + +/* Chip features. */ +typedef enum _gceFEATURE +{ + gcvFEATURE_PIPE_2D, + gcvFEATURE_PIPE_3D, + gcvFEATURE_PIPE_VG, + gcvFEATURE_DC, + gcvFEATURE_HIGH_DYNAMIC_RANGE, + gcvFEATURE_MODULE_CG, + gcvFEATURE_MIN_AREA, + gcvFEATURE_BUFFER_INTERLEAVING, + gcvFEATURE_BYTE_WRITE_2D, + gcvFEATURE_ENDIANNESS_CONFIG, + gcvFEATURE_DUAL_RETURN_BUS, + gcvFEATURE_DEBUG_MODE, + gcvFEATURE_YUY2_RENDER_TARGET, + gcvFEATURE_FRAGMENT_PROCESSOR, + gcvFEATURE_2DPE20, + gcvFEATURE_FAST_CLEAR, + gcvFEATURE_YUV420_TILER, + gcvFEATURE_YUY2_AVERAGING, + gcvFEATURE_FLIP_Y, + gcvFEATURE_EARLY_Z, + gcvFEATURE_Z_COMPRESSION, + gcvFEATURE_MSAA, + gcvFEATURE_SPECIAL_ANTI_ALIASING, + gcvFEATURE_SPECIAL_MSAA_LOD, + gcvFEATURE_422_TEXTURE_COMPRESSION, + gcvFEATURE_DXT_TEXTURE_COMPRESSION, + gcvFEATURE_ETC1_TEXTURE_COMPRESSION, + gcvFEATURE_CORRECT_TEXTURE_CONVERTER, + gcvFEATURE_TEXTURE_8K, + gcvFEATURE_SCALER, + gcvFEATURE_YUV420_SCALER, + gcvFEATURE_SHADER_HAS_W, + gcvFEATURE_SHADER_HAS_SIGN, + gcvFEATURE_SHADER_HAS_FLOOR, + gcvFEATURE_SHADER_HAS_CEIL, + gcvFEATURE_SHADER_HAS_SQRT, + gcvFEATURE_SHADER_HAS_TRIG, + gcvFEATURE_VAA, + gcvFEATURE_HZ, + gcvFEATURE_CORRECT_STENCIL, + gcvFEATURE_VG20, + gcvFEATURE_VG_FILTER, + gcvFEATURE_VG21, + gcvFEATURE_VG_DOUBLE_BUFFER, + gcvFEATURE_MC20, + gcvFEATURE_SUPER_TILED, + + gcvFEATURE_2D_FILTERBLIT_PLUS_ALPHABLEND, + gcvFEATURE_2D_DITHER, + gcvFEATURE_2D_A8_TARGET, + gcvFEATURE_2D_FILTERBLIT_FULLROTATION, + gcvFEATURE_2D_BITBLIT_FULLROTATION, + + gcvFEATURE_WIDE_LINE, + gcvFEATURE_FC_FLUSH_STALL, + + gcvFEATURE_FULL_DIRECTFB, + gcvFEATURE_HALF_FLOAT_PIPE, + gcvFEATURE_LINE_LOOP, + gcvFEATURE_2D_YUV_BLIT, + gcvFEATURE_2D_TILING, +} +gceFEATURE; + +/* Chip Power Status. */ +typedef enum _gceCHIPPOWERSTATE +{ + gcvPOWER_ON, + gcvPOWER_OFF, + gcvPOWER_IDLE, + gcvPOWER_SUSPEND, + gcvPOWER_ON_BROADCAST, + gcvPOWER_SUSPEND_ATPOWERON, + gcvPOWER_OFF_ATPOWERON, + gcvPOWER_IDLE_BROADCAST, + gcvPOWER_SUSPEND_BROADCAST, + gcvPOWER_OFF_BROADCAST, + gcvPOWER_OFF_RECOVERY, +} +gceCHIPPOWERSTATE; + +/* Surface types. */ +typedef enum _gceSURF_TYPE +{ + gcvSURF_TYPE_UNKNOWN, + gcvSURF_INDEX, + gcvSURF_VERTEX, + gcvSURF_TEXTURE, + gcvSURF_RENDER_TARGET, + gcvSURF_DEPTH, + gcvSURF_BITMAP, + gcvSURF_TILE_STATUS, + gcvSURF_MASK, + gcvSURF_SCISSOR, + gcvSURF_HIERARCHICAL_DEPTH, + gcvSURF_NUM_TYPES, /* Make sure this is the last one! */ + + /* Combinations. */ + gcvSURF_NO_TILE_STATUS = 0x100, + gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET + | gcvSURF_NO_TILE_STATUS, + gcvSURF_DEPTH_NO_TILE_STATUS = gcvSURF_DEPTH + | gcvSURF_NO_TILE_STATUS, +} +gceSURF_TYPE; + +typedef enum _gceSURF_COLOR_TYPE +{ + gcvSURF_COLOR_UNKNOWN, + gcvSURF_COLOR_LINEAR = 0x01, + gcvSURF_COLOR_ALPHA_PRE = 0x02, +} +gceSURF_COLOR_TYPE; + +/* Rotation. */ +typedef enum _gceSURF_ROTATION +{ + gcvSURF_0_DEGREE, + gcvSURF_90_DEGREE, + gcvSURF_180_DEGREE, + gcvSURF_270_DEGREE, + gcvSURF_FLIP_X, + gcvSURF_FLIP_Y, +} +gceSURF_ROTATION; + +/* Surface formats. */ +typedef enum _gceSURF_FORMAT +{ + /* Unknown format. */ + gcvSURF_UNKNOWN, + + /* Palettized formats. */ + gcvSURF_INDEX1 = 100, + gcvSURF_INDEX4, + gcvSURF_INDEX8, + + /* RGB formats. */ + gcvSURF_A2R2G2B2 = 200, + gcvSURF_R3G3B2, + gcvSURF_A8R3G3B2, + gcvSURF_X4R4G4B4, + gcvSURF_A4R4G4B4, + gcvSURF_R4G4B4A4, + gcvSURF_X1R5G5B5, + gcvSURF_A1R5G5B5, + gcvSURF_R5G5B5A1, + gcvSURF_R5G6B5, + gcvSURF_R8G8B8, + gcvSURF_X8R8G8B8, + gcvSURF_A8R8G8B8, + gcvSURF_R8G8B8A8, + gcvSURF_G8R8G8B8, + gcvSURF_R8G8B8G8, + gcvSURF_X2R10G10B10, + gcvSURF_A2R10G10B10, + gcvSURF_X12R12G12B12, + gcvSURF_A12R12G12B12, + gcvSURF_X16R16G16B16, + gcvSURF_A16R16G16B16, + gcvSURF_R8G8B8X8, + gcvSURF_R5G5B5X1, + gcvSURF_R4G4B4X4, + + /* BGR formats. */ + gcvSURF_A4B4G4R4 = 300, + gcvSURF_A1B5G5R5, + gcvSURF_B5G6R5, + gcvSURF_B8G8R8, + gcvSURF_X8B8G8R8, + gcvSURF_A8B8G8R8, + gcvSURF_A2B10G10R10, + gcvSURF_A16B16G16R16, + gcvSURF_G16R16, + gcvSURF_B4G4R4A4, + gcvSURF_B5G5R5A1, + gcvSURF_B8G8R8X8, + gcvSURF_B8G8R8A8, + gcvSURF_X4B4G4R4, + gcvSURF_X1B5G5R5, + gcvSURF_B4G4R4X4, + gcvSURF_B5G5R5X1, + + /* Compressed formats. */ + gcvSURF_DXT1 = 400, + gcvSURF_DXT2, + gcvSURF_DXT3, + gcvSURF_DXT4, + gcvSURF_DXT5, + gcvSURF_CXV8U8, + gcvSURF_ETC1, + + /* YUV formats. */ + gcvSURF_YUY2 = 500, + gcvSURF_UYVY, + gcvSURF_YV12, + gcvSURF_I420, + gcvSURF_NV12, + gcvSURF_NV21, + gcvSURF_NV16, + gcvSURF_NV61, + gcvSURF_YVYU, + gcvSURF_VYUY, + + /* Depth formats. */ + gcvSURF_D16 = 600, + gcvSURF_D24S8, + gcvSURF_D32, + gcvSURF_D24X8, + + /* Alpha formats. */ + gcvSURF_A4 = 700, + gcvSURF_A8, + gcvSURF_A12, + gcvSURF_A16, + gcvSURF_A32, + gcvSURF_A1, + + /* Luminance formats. */ + gcvSURF_L4 = 800, + gcvSURF_L8, + gcvSURF_L12, + gcvSURF_L16, + gcvSURF_L32, + gcvSURF_L1, + + /* Alpha/Luminance formats. */ + gcvSURF_A4L4 = 900, + gcvSURF_A2L6, + gcvSURF_A8L8, + gcvSURF_A4L12, + gcvSURF_A12L12, + gcvSURF_A16L16, + + /* Bump formats. */ + gcvSURF_L6V5U5 = 1000, + gcvSURF_V8U8, + gcvSURF_X8L8V8U8, + gcvSURF_Q8W8V8U8, + gcvSURF_A2W10V10U10, + gcvSURF_V16U16, + gcvSURF_Q16W16V16U16, + + /* Floating point formats. */ + gcvSURF_R16F = 1100, + gcvSURF_G16R16F, + gcvSURF_A16B16G16R16F, + gcvSURF_R32F, + gcvSURF_G32R32F, + gcvSURF_A32B32G32R32F, + +#if 0 + /* FIXME: remove HDR support for now. */ + /* HDR formats. */ + gcvSURF_HDR7E3 = 1200, + gcvSURF_HDR6E4, + gcvSURF_HDR5E5, + gcvSURF_HDR6E5, +#endif +} +gceSURF_FORMAT; + +/* Pixel swizzle modes. */ +typedef enum _gceSURF_SWIZZLE +{ + gcvSURF_NOSWIZZLE, + gcvSURF_ARGB, + gcvSURF_ABGR, + gcvSURF_RGBA, + gcvSURF_BGRA +} +gceSURF_SWIZZLE; + +/* Transparency modes. */ +typedef enum _gceSURF_TRANSPARENCY +{ + /* Valid only for PE 1.0 */ + gcvSURF_OPAQUE, + gcvSURF_SOURCE_MATCH, + gcvSURF_SOURCE_MASK, + gcvSURF_PATTERN_MASK, +} +gceSURF_TRANSPARENCY; + +/* Transparency modes. */ +typedef enum _gce2D_TRANSPARENCY +{ + /* Valid only for PE 2.0 */ + gcv2D_OPAQUE, + gcv2D_KEYED, + gcv2D_MASKED +} +gce2D_TRANSPARENCY; + +/* Mono packing modes. */ +typedef enum _gceSURF_MONOPACK +{ + gcvSURF_PACKED8, + gcvSURF_PACKED16, + gcvSURF_PACKED32, + gcvSURF_UNPACKED, +} +gceSURF_MONOPACK; + +/* Blending modes. */ +typedef enum _gceSURF_BLEND_MODE +{ + /* Porter-Duff blending modes. */ + /* Fsrc Fdst */ + gcvBLEND_CLEAR, /* 0 0 */ + gcvBLEND_SRC, /* 1 0 */ + gcvBLEND_DST, /* 0 1 */ + gcvBLEND_SRC_OVER_DST, /* 1 1 - Asrc */ + gcvBLEND_DST_OVER_SRC, /* 1 - Adst 1 */ + gcvBLEND_SRC_IN_DST, /* Adst 0 */ + gcvBLEND_DST_IN_SRC, /* 0 Asrc */ + gcvBLEND_SRC_OUT_DST, /* 1 - Adst 0 */ + gcvBLEND_DST_OUT_SRC, /* 0 1 - Asrc */ + gcvBLEND_SRC_ATOP_DST, /* Adst 1 - Asrc */ + gcvBLEND_DST_ATOP_SRC, /* 1 - Adst Asrc */ + gcvBLEND_SRC_XOR_DST, /* 1 - Adst 1 - Asrc */ + + /* Special blending modes. */ + gcvBLEND_SET, /* DST = 1 */ + gcvBLEND_SUB /* DST = DST * (1 - SRC) */ +} +gceSURF_BLEND_MODE; + +/* Per-pixel alpha modes. */ +typedef enum _gceSURF_PIXEL_ALPHA_MODE +{ + gcvSURF_PIXEL_ALPHA_STRAIGHT, + gcvSURF_PIXEL_ALPHA_INVERSED +} +gceSURF_PIXEL_ALPHA_MODE; + +/* Global alpha modes. */ +typedef enum _gceSURF_GLOBAL_ALPHA_MODE +{ + gcvSURF_GLOBAL_ALPHA_OFF, + gcvSURF_GLOBAL_ALPHA_ON, + gcvSURF_GLOBAL_ALPHA_SCALE +} +gceSURF_GLOBAL_ALPHA_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gceSURF_PIXEL_COLOR_MODE +{ + gcvSURF_COLOR_STRAIGHT, + gcvSURF_COLOR_MULTIPLY +} +gceSURF_PIXEL_COLOR_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE +{ + gcv2D_COLOR_MULTIPLY_DISABLE, + gcv2D_COLOR_MULTIPLY_ENABLE +} +gce2D_PIXEL_COLOR_MULTIPLY_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE +{ + gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE, + gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA, + gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR +} +gce2D_GLOBAL_COLOR_MULTIPLY_MODE; + +/* Alpha blending factor modes. */ +typedef enum _gceSURF_BLEND_FACTOR_MODE +{ + gcvSURF_BLEND_ZERO, + gcvSURF_BLEND_ONE, + gcvSURF_BLEND_STRAIGHT, + gcvSURF_BLEND_INVERSED, + gcvSURF_BLEND_COLOR, + gcvSURF_BLEND_COLOR_INVERSED, + gcvSURF_BLEND_SRC_ALPHA_SATURATED, + gcvSURF_BLEND_STRAIGHT_NO_CROSS, + gcvSURF_BLEND_INVERSED_NO_CROSS, + gcvSURF_BLEND_COLOR_NO_CROSS, + gcvSURF_BLEND_COLOR_INVERSED_NO_CROSS, + gcvSURF_BLEND_SRC_ALPHA_SATURATED_CROSS +} +gceSURF_BLEND_FACTOR_MODE; + +/* Alpha blending porter duff rules. */ +typedef enum _gce2D_PORTER_DUFF_RULE +{ + gcvPD_CLEAR, + gcvPD_SRC, + gcvPD_SRC_OVER, + gcvPD_DST_OVER, + gcvPD_SRC_IN, + gcvPD_DST_IN, + gcvPD_SRC_OUT, + gcvPD_DST_OUT, + gcvPD_SRC_ATOP, + gcvPD_DST_ATOP, + gcvPD_ADD, + gcvPD_XOR, + gcvPD_DST +} +gce2D_PORTER_DUFF_RULE; + +/* Alpha blending factor modes. */ +typedef enum _gce2D_YUV_COLOR_MODE +{ + gcv2D_YUV_601, + gcv2D_YUV_709 +} +gce2D_YUV_COLOR_MODE; + +/* 2D Rotation and flipping. */ +typedef enum _gce2D_ORIENTATION +{ + gcv2D_0_DEGREE, + gcv2D_90_DEGREE, + gcv2D_180_DEGREE, + gcv2D_270_DEGREE, + gcv2D_X_FLIP, + gcv2D_Y_FLIP +} +gce2D_ORIENTATION; + +typedef enum _gce2D_COMMAND +{ + gcv2D_CLEAR, + gcv2D_LINE, + gcv2D_BLT, + gcv2D_STRETCH, + gcv2D_HOR_FILTER, + gcv2D_VER_FILTER, + gcv2D_MULTI_SOURCE_BLEND, +} +gce2D_COMMAND; + +#ifndef VIVANTE_NO_3D +/* Texture functions. */ +typedef enum _gceTEXTURE_FUNCTION +{ + gcvTEXTURE_DUMMY = 0, + gcvTEXTURE_REPLACE = 0, + gcvTEXTURE_MODULATE, + gcvTEXTURE_ADD, + gcvTEXTURE_ADD_SIGNED, + gcvTEXTURE_INTERPOLATE, + gcvTEXTURE_SUBTRACT, + gcvTEXTURE_DOT3 +} +gceTEXTURE_FUNCTION; + +/* Texture sources. */ +typedef enum _gceTEXTURE_SOURCE +{ + gcvCOLOR_FROM_TEXTURE, + gcvCOLOR_FROM_CONSTANT_COLOR, + gcvCOLOR_FROM_PRIMARY_COLOR, + gcvCOLOR_FROM_PREVIOUS_COLOR +} +gceTEXTURE_SOURCE; + +/* Texture source channels. */ +typedef enum _gceTEXTURE_CHANNEL +{ + gcvFROM_COLOR, + gcvFROM_ONE_MINUS_COLOR, + gcvFROM_ALPHA, + gcvFROM_ONE_MINUS_ALPHA +} +gceTEXTURE_CHANNEL; +#endif /* VIVANTE_NO_3D */ + +/* Filter types. */ +typedef enum _gceFILTER_TYPE +{ + gcvFILTER_SYNC, + gcvFILTER_BLUR, + gcvFILTER_USER +} +gceFILTER_TYPE; + +/* Filter pass types. */ +typedef enum _gceFILTER_PASS_TYPE +{ + gcvFILTER_HOR_PASS, + gcvFILTER_VER_PASS +} +gceFILTER_PASS_TYPE; + +/* Endian hints. */ +typedef enum _gceENDIAN_HINT +{ + gcvENDIAN_NO_SWAP = 0, + gcvENDIAN_SWAP_WORD, + gcvENDIAN_SWAP_DWORD +} +gceENDIAN_HINT; + +/* Tiling modes. */ +typedef enum _gceTILING +{ + gcvLINEAR, + gcvTILED, + gcvSUPERTILED, + gcvMULTI_TILED, + gcvMULTI_SUPERTILED, +} +gceTILING; + +/* 2D pattern type. */ +typedef enum _gce2D_PATTERN +{ + gcv2D_PATTERN_SOLID = 0, + gcv2D_PATTERN_MONO, + gcv2D_PATTERN_COLOR, + gcv2D_PATTERN_INVALID +} +gce2D_PATTERN; + +/* 2D source type. */ +typedef enum _gce2D_SOURCE +{ + gcv2D_SOURCE_MASKED = 0, + gcv2D_SOURCE_MONO, + gcv2D_SOURCE_COLOR, + gcv2D_SOURCE_INVALID +} +gce2D_SOURCE; + +/* Pipes. */ +typedef enum _gcePIPE_SELECT +{ + gcvPIPE_INVALID = ~0, + gcvPIPE_3D = 0, + gcvPIPE_2D +} +gcePIPE_SELECT; + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoCONTEXT * gcoCONTEXT; +typedef struct _gcoCMDBUF * gcoCMDBUF; +typedef struct _gcoQUEUE * gcoQUEUE; +typedef struct _gcsHAL_INTERFACE * gcsHAL_INTERFACE_PTR; +typedef struct gcs2D_PROFILE * gcs2D_PROFILE_PTR; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_enum_h_ */ + + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_mem.h b/kernel_drivers/v2/hal/inc/gc_hal_mem.h new file mode 100644 index 0000000..bf0c40f --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_mem.h @@ -0,0 +1,471 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file for the local memory management. +*/ + +#ifndef __gc_hal_mem_h_ +#define __gc_hal_mem_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* +** Usage: + + The macros to declare MemPool type and functions are + gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) + + The data structures for MemPool are + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; + + The MemPool constructor and destructor functions are + gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT); + gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *); + gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL); + gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *); + gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT); + gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *); + + FS: for Fixed-Size data structures + VS: for Variable-size data structures + AFS: for Array of Fixed-Size data structures + + + // Example 1: For a fixed-size data structure, struct gcsNode. + // It is used locally in a file, so the functions are static without prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type. + // The second armument is the short name used in the fuctions. + gcmMEM_DeclareFSMemPool(struct gcsNode, Node, ); + + // The previous macro creates two inline functions, + // _AllocateNode and _FreeNode. + + // In function or struct + gcsMEM_FS_MEM_POOL nodeMemPool; + + // In function, + struct gcsNode * node; + gceSTATUS status; + + // Before using the memory pool, initialize it. + // The second argument is the gcoOS object. + // The third argument is the number of data structures to allocate for each chunk. + status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode)); + ... + + // Allocate a node. + status = _AllocateNode(nodeMemPool, &node); + ... + // Free a node. + _FreeNode(nodeMemPool, node); + + // After using the memory pool, free it. + gcfMEM_FreeFSMemPool(&nodeMemPool); + + + // Example 2: For array of fixed-size data structures, struct gcsNode. + // It is used in several files, so the functions are extern with prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type, and the second one is the short name + // used in the fuctions. + gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt); + + // The previous macro creates two inline functions, + // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray. + + // In function or struct + gcsMEM_AFS_MEM_POOL nodeArrayMemPool; + + // In function, + struct gcsNode * nodeArray; + gceSTATUS status; + + // Before using the array memory pool, initialize it. + // The second argument is the gcoOS object, the third is the number of data + // structures to allocate for each chunk. + status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode)); + ... + + // Allocate a node array of size 100. + status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100); + ... + // Free a node array. + gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray); + + // After using the array memory pool, free it. + gcfMEM_FreeAFSMemPool(&nodeArrayMemPool); + +*******************************************************************************/ + +/******************************************************************************* +** To switch back to use gcoOS_Allocate and gcoOS_Free, add +** #define USE_LOCAL_MEMORY_POOL 0 +** before including this file. +*******************************************************************************/ +#ifndef USE_LOCAL_MEMORY_POOL +/* + USE_LOCAL_MEMORY_POOL + + This define enables the local memory management to improve performance. +*/ +#define USE_LOCAL_MEMORY_POOL 1 +#endif + +/******************************************************************************* +** Memory Pool Data Structures +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; +#else + typedef gcoOS gcsMEM_FS_MEM_POOL; + typedef gcoOS gcsMEM_VS_MEM_POOL; + typedef gcoOS gcsMEM_AFS_MEM_POOL; +#endif + +/******************************************************************************* +** Memory Pool Macros +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName##List( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * FirstPointer, \ + Type * LastPointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer)); \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + return(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ + Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size)); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + return(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer)); \ +} + +#else + +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size)); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + return(gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + return(gcoOS_Free(MemPool, Pointer)); \ +} +#endif + +/******************************************************************************* +** Memory Pool Data Functions +*******************************************************************************/ +gceSTATUS +gcfMEM_InitFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_FSMemPoolGetANode( + IN gcsMEM_FS_MEM_POOL MemPool, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeANode( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeAList( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER FirstNode, + IN gctPOINTER LastNode + ); + +gceSTATUS +gcfMEM_InitVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT BlockSize, + IN gctBOOL RecycleFreeNode + ); + +gceSTATUS +gcfMEM_FreeVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_VSMemPoolGetANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctUINT Size, + IN gctUINT Alignment, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_VSMemPoolFreeANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_InitAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool + ); + +gceSTATUS +gcfMEM_AFSMemPoolGetANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctUINT Count, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_AFSMemPoolFreeANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_mem_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_options.h b/kernel_drivers/v2/hal/inc/gc_hal_options.h new file mode 100644 index 0000000..3e3a833 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_options.h @@ -0,0 +1,263 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_options_h_ +#define __gc_hal_options_h_ + +/* + USE_NEW_LINUX_SIGNAL + + This define enables the Linux kernel signaling between kernel and user. +*/ +#ifndef USE_NEW_LINUX_SIGNAL +# define USE_NEW_LINUX_SIGNAL 0 +#endif + +/* + NO_USER_DIRECT_ACCESS_FROM_KERNEL + + This define enables the Linux kernel behavior accessing user memory. +*/ +#ifndef NO_USER_DIRECT_ACCESS_FROM_KERNEL +# define NO_USER_DIRECT_ACCESS_FROM_KERNEL 0 +#endif + +/* + VIVANTE_PROFILER + + This define enables the profiler. +*/ +#ifndef VIVANTE_PROFILER +# define VIVANTE_PROFILER 0 +#endif + +/* + gcdUSE_VG + + Enable VG HAL layer (only for GC350). +*/ +#ifndef gcdUSE_VG +# define gcdUSE_VG 0 +#endif + +/* + USE_SW_FB + + Set to 1 if the frame buffer memory cannot be accessed by the GPU. +*/ +#ifndef USE_SW_FB +#define USE_SW_FB 0 +#endif + +/* + USE_SHADER_SYMBOL_TABLE + + This define enables the symbol table in shader object. +*/ +#define USE_SHADER_SYMBOL_TABLE 1 + +/* + USE_SUPER_SAMPLING + + This define enables super-sampling support. +*/ +#define USE_SUPER_SAMPLING 0 + +/* PROFILE_HAL_COUNTERS, PROFILE_HW_COUNTERS, PROFILE_SHADER_COUNTERS are not runtime configurable. */ +/* + PROFILE_HAL_COUNTERS + + This define enables HAL counter profiling support. + HW and SHADER Counter profiling depends on this. +*/ +/* +#define PROFILE_HAL_COUNTERS 1 +*/ +/* + PROFILE_HW_COUNTERS + + This define enables HW counter profiling support. +*/ +/* +#define PROFILE_HW_COUNTERS 1 +*/ +/* + PROFILE_SHADER_COUNTERS + + This define enables SHADER counter profiling support. +*/ +/* +#define PROFILE_SHADER_COUNTERS 1 +*/ +/* + COMMAND_PROCESSOR_VERSION + + The version of the command buffer and task manager. +*/ +#define COMMAND_PROCESSOR_VERSION 1 + +/* + gcdDUMP + + When set to 1, a dump of all states and memory uploads, as well as other + hardware related execution will be printed to the debug console. This + data can be used for playing back applications. +*/ +#define gcdDUMP 0 + +/* + gcdDUMP_API + + When set to 1, a high level dump of the EGL and GL/VG APs's are + captured. +*/ +#define gcdDUMP_API 0 + +/* + gcdDUMP_IN_KERNEL + + When set to 1, all dumps will happen in the kernel. This is handy if + you want the kernel to dump its command buffers as well and the data + needs to be in sync. +*/ +#define gcdDUMP_IN_KERNEL 0 + +/* + gcdDUMP_COMMAND + + When set to non-zero, the command queue will dump all incoming command + and context buffers as well as all other modifications to the command + queue. +*/ +#define gcdDUMP_COMMAND 0 + +/* + gcdNULL_DRIVER +*/ +#define gcdNULL_DRIVER 0 + +/* + gcdENABLE_TIMEOUT_DETECTION + + Enable timeout detection. +*/ +#define gcdENABLE_TIMEOUT_DETECTION 0 + +/* + gcdCMD_BUFFERS + + Number of command buffers to use per client. Each command buffer is 32kB in + size. +*/ +#define gcdCMD_BUFFERS 2 + +/* + gcdPOWER_CONTROL_DELAY + + The delay in milliseconds required to wait until the GPU has woke up from a + suspend or power-down state. This is system dependent because the bus clock + also needs to be stabalize. +*/ +#define gcdPOWER_CONTROL_DELAY 1 + +/* + gcdMMU_SIZE + + Size of the MMU page table in bytes. Each 4 bytes can hold 4kB worth of + virtual data. +*/ +#define gcdMMU_SIZE (128 << 10) + +/* + gcdSECURE_USER + + Use logical addresses instead of physical addresses in user land. In this + case a hint table is created for both command buffers and context buffers, + and that hint table will be used to patch up those buffers in the kernel + when they are ready to submit. +*/ +#define gcdSECURE_USER 0 + +/* + gcdSECURE_CACHE_SLOTS + + Number of slots in the logical to DMA address cache table. Each time a + logical address needs to be translated into a DMA address for the GPU, this + cache will be walked. The replacement scheme is LRU. +*/ +#define gcdSECURE_CACHE_SLOTS 64 + +/* + gcdREGISTER_ACCESS_FROM_USER + + Set to 1 to allow IOCTL calls to get through from user land. This should + only be in debug or development drops. +*/ +#ifndef gcdREGISTER_ACCESS_FROM_USER +# define gcdREGISTER_ACCESS_FROM_USER 1 +#endif + +/* + gcdHEAP_SIZE + + Set the allocation size for the internal heaps. Each time a heap is full, + a new heap will be allocated with this minmimum amount of bytes. The bigger + this size, the fewer heaps there are to allocate, the better the + performance. However, heaps won't be freed until they are completely free, + so there might be some more memory waste if the size is too big. +*/ +#define gcdHEAP_SIZE (64 << 10) + +/* + gcdNO_POWER_MANAGEMENT + + This define disables the power management code. +*/ +#ifndef gcdNO_POWER_MANAGEMENT +# define gcdNO_POWER_MANAGEMENT 0 +#endif + +/* + gcdFPGA_BUILD + + This define enables work arounds for FPGA images. +*/ +#if !defined(gcdFPGA_BUILD) +# define gcdFPGA_BUILD 0 +#endif + +/* + gcdGPU_TIMEOUT + + This define specified the number of milliseconds the system will wait before + it broadcasts the GPU is stuck. In other words, it will define the timeout + of any operation that needs to wait for the GPU. + + If the value is 0, no timeout will be checked for. +*/ +#if !defined(gcdGPU_TIMEOUT) +# define gcdGPU_TIMEOUT 0 +#endif + +#endif /* __gc_hal_options_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_profiler.h b/kernel_drivers/v2/hal/inc/gc_hal_profiler.h new file mode 100644 index 0000000..70d0c69 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_profiler.h @@ -0,0 +1,817 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + +#ifndef __gc_hal_profiler_h_ +#define __gc_hal_profiler_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLVERTEX_OBJECT 10 +#define GLVERTEX_OBJECT_BYTES 11 + +#define GLINDEX_OBJECT 20 +#define GLINDEX_OBJECT_BYTES 21 + +#define GLTEXTURE_OBJECT 30 +#define GLTEXTURE_OBJECT_BYTES 31 + +#if VIVANTE_PROFILER +#define gcmPROFILE_GC(Hal, Enum, Value) gcoPROFILER_Count(Hal, Enum, Value) +#else +#define gcmPROFILE_GC(Hal, Enum, Value) do { } while (gcvFALSE) +#endif + +#ifndef gcdNEW_PROFILER_FILE +#define gcdNEW_PROFILER_FILE 1 +#endif + +#ifdef gcdNEW_PROFILER_FILE + +/* Category Constants. */ +#define VPHEADER 0x010000 +#define VPG_INFO 0x020000 +#define VPG_TIME 0x030000 +#define VPG_MEM 0x040000 +#define VPG_ES11 0x050000 +#define VPG_ES20 0x060000 +#define VPG_VG11 0x070000 +#define VPG_HAL 0x080000 +#define VPG_HW 0x090000 +#define VPG_GPU 0x0a0000 +#define VPG_VS 0x0b0000 +#define VPG_PS 0x0c0000 +#define VPG_PA 0x0d0000 +#define VPG_SETUP 0x0e0000 +#define VPG_RA 0x0f0000 +#define VPG_TX 0x100000 +#define VPG_PE 0x110000 +#define VPG_MC 0x120000 +#define VPG_AXI 0x130000 +#define VPG_PROG 0x140000 +#define VPG_PVS 0x150000 +#define VPG_PPS 0x160000 +#define VPG_FRAME 0x170000 +#define VPG_END 0xff0000 + +/* Info. */ +#define VPC_INFOCOMPANY (VPG_INFO + 1) +#define VPC_INFOVERSION (VPG_INFO + 2) +#define VPC_INFORENDERER (VPG_INFO + 3) +#define VPC_INFOREVISION (VPG_INFO + 4) +#define VPC_INFODRIVER (VPG_INFO + 5) + +/* Counter Constants. */ +#define VPC_ELAPSETIME 0x030001 +#define VPC_CPUTIME 0x030002 + +#define VPC_MEMMAXRES 0x040001 +#define VPC_MEMSHARED 0x040002 +#define VPC_MEMUNSHAREDDATA 0x040003 +#define VPC_MEMUNSHAREDSTACK 0x040004 + +/* OpenGL ES11 Counters. */ +#define VPC_ES11ACTIVETEXTURE (VPG_ES11 + 1) +#define VPC_ES11ALPHAFUNC (VPG_ES11 + 2) +#define VPC_ES11ALPHAFUNCX (VPG_ES11 + 3) +#define VPC_ES11BINDBUFFER (VPG_ES11 + 4) +#define VPC_ES11BINDTEXTURE (VPG_ES11 + 5) +#define VPC_ES11BLENDFUNC (VPG_ES11 + 6) +#define VPC_ES11BUFFERDATA (VPG_ES11 + 7) +#define VPC_ES11BUFFERSUBDATA (VPG_ES11 + 8) +#define VPC_ES11CLEAR (VPG_ES11 + 9) +#define VPC_ES11CLEARCOLOR (VPG_ES11 + 10) +#define VPC_ES11CLEARCOLORX (VPG_ES11 + 11) +#define VPC_ES11CLEARDEPTHF (VPG_ES11 + 12) +#define VPC_ES11CLEARDEPTHX (VPG_ES11 + 13) +#define VPC_ES11CLEARSTENCIL (VPG_ES11 + 14) +#define VPC_ES11CLIENTACTIVETEXTURE (VPG_ES11 + 15) +#define VPC_ES11CLIPPLANEF (VPG_ES11 + 16) +#define VPC_ES11CLIPPLANEX (VPG_ES11 + 17) +#define VPC_ES11COLOR4F (VPG_ES11 + 18) +#define VPC_ES11COLOR4UB (VPG_ES11 + 19) +#define VPC_ES11COLOR4X (VPG_ES11 + 20) +#define VPC_ES11COLORMASK (VPG_ES11 + 21) +#define VPC_ES11COLORPOINTER (VPG_ES11 + 22) +#define VPC_ES11COMPRESSEDTEXIMAGE2D (VPG_ES11 + 23) +#define VPC_ES11COMPRESSEDTEXSUBIMAGE2D (VPG_ES11 + 24) +#define VPC_ES11COPYTEXIMAGE2D (VPG_ES11 + 25) +#define VPC_ES11COPYTEXSUBIMAGE2D (VPG_ES11 + 26) +#define VPC_ES11CULLFACE (VPG_ES11 + 27) +#define VPC_ES11DELETEBUFFERS (VPG_ES11 + 28) +#define VPC_ES11DELETETEXTURES (VPG_ES11 + 29) +#define VPC_ES11DEPTHFUNC (VPG_ES11 + 30) +#define VPC_ES11DEPTHMASK (VPG_ES11 + 31) +#define VPC_ES11DEPTHRANGEF (VPG_ES11 + 32) +#define VPC_ES11DEPTHRANGEX (VPG_ES11 + 33) +#define VPC_ES11DISABLE (VPG_ES11 + 34) +#define VPC_ES11DISABLECLIENTSTATE (VPG_ES11 + 35) +#define VPC_ES11DRAWARRAYS (VPG_ES11 + 36) +#define VPC_ES11DRAWELEMENTS (VPG_ES11 + 37) +#define VPC_ES11ENABLE (VPG_ES11 + 38) +#define VPC_ES11ENABLECLIENTSTATE (VPG_ES11 + 39) +#define VPC_ES11FINISH (VPG_ES11 + 40) +#define VPC_ES11FLUSH (VPG_ES11 + 41) +#define VPC_ES11FOGF (VPG_ES11 + 42) +#define VPC_ES11FOGFV (VPG_ES11 + 43) +#define VPC_ES11FOGX (VPG_ES11 + 44) +#define VPC_ES11FOGXV (VPG_ES11 + 45) +#define VPC_ES11FRONTFACE (VPG_ES11 + 46) +#define VPC_ES11FRUSTUMF (VPG_ES11 + 47) +#define VPC_ES11FRUSTUMX (VPG_ES11 + 48) +#define VPC_ES11GENBUFFERS (VPG_ES11 + 49) +#define VPC_ES11GENTEXTURES (VPG_ES11 + 50) +#define VPC_ES11GETBOOLEANV (VPG_ES11 + 51) +#define VPC_ES11GETBUFFERPARAMETERIV (VPG_ES11 + 52) +#define VPC_ES11GETCLIPPLANEF (VPG_ES11 + 53) +#define VPC_ES11GETCLIPPLANEX (VPG_ES11 + 54) +#define VPC_ES11GETERROR (VPG_ES11 + 55) +#define VPC_ES11GETFIXEDV (VPG_ES11 + 56) +#define VPC_ES11GETFLOATV (VPG_ES11 + 57) +#define VPC_ES11GETINTEGERV (VPG_ES11 + 58) +#define VPC_ES11GETLIGHTFV (VPG_ES11 + 59) +#define VPC_ES11GETLIGHTXV (VPG_ES11 + 60) +#define VPC_ES11GETMATERIALFV (VPG_ES11 + 61) +#define VPC_ES11GETMATERIALXV (VPG_ES11 + 62) +#define VPC_ES11GETPOINTERV (VPG_ES11 + 63) +#define VPC_ES11GETSTRING (VPG_ES11 + 64) +#define VPC_ES11GETTEXENVFV (VPG_ES11 + 65) +#define VPC_ES11GETTEXENVIV (VPG_ES11 + 66) +#define VPC_ES11GETTEXENVXV (VPG_ES11 + 67) +#define VPC_ES11GETTEXPARAMETERFV (VPG_ES11 + 68) +#define VPC_ES11GETTEXPARAMETERIV (VPG_ES11 + 69) +#define VPC_ES11GETTEXPARAMETERXV (VPG_ES11 + 70) +#define VPC_ES11HINT (VPG_ES11 + 71) +#define VPC_ES11ISBUFFER (VPG_ES11 + 72) +#define VPC_ES11ISENABLED (VPG_ES11 + 73) +#define VPC_ES11ISTEXTURE (VPG_ES11 + 74) +#define VPC_ES11LIGHTF (VPG_ES11 + 75) +#define VPC_ES11LIGHTFV (VPG_ES11 + 76) +#define VPC_ES11LIGHTMODELF (VPG_ES11 + 77) +#define VPC_ES11LIGHTMODELFV (VPG_ES11 + 78) +#define VPC_ES11LIGHTMODELX (VPG_ES11 + 79) +#define VPC_ES11LIGHTMODELXV (VPG_ES11 + 80) +#define VPC_ES11LIGHTX (VPG_ES11 + 81) +#define VPC_ES11LIGHTXV (VPG_ES11 + 82) +#define VPC_ES11LINEWIDTH (VPG_ES11 + 83) +#define VPC_ES11LINEWIDTHX (VPG_ES11 + 84) +#define VPC_ES11LOADIDENTITY (VPG_ES11 + 85) +#define VPC_ES11LOADMATRIXF (VPG_ES11 + 86) +#define VPC_ES11LOADMATRIXX (VPG_ES11 + 87) +#define VPC_ES11LOGICOP (VPG_ES11 + 88) +#define VPC_ES11MATERIALF (VPG_ES11 + 89) +#define VPC_ES11MATERIALFV (VPG_ES11 + 90) +#define VPC_ES11MATERIALX (VPG_ES11 + 91) +#define VPC_ES11MATERIALXV (VPG_ES11 + 92) +#define VPC_ES11MATRIXMODE (VPG_ES11 + 93) +#define VPC_ES11MULTITEXCOORD4F (VPG_ES11 + 94) +#define VPC_ES11MULTITEXCOORD4X (VPG_ES11 + 95) +#define VPC_ES11MULTMATRIXF (VPG_ES11 + 96) +#define VPC_ES11MULTMATRIXX (VPG_ES11 + 97) +#define VPC_ES11NORMAL3F (VPG_ES11 + 98) +#define VPC_ES11NORMAL3X (VPG_ES11 + 99) +#define VPC_ES11NORMALPOINTER (VPG_ES11 + 100) +#define VPC_ES11ORTHOF (VPG_ES11 + 101) +#define VPC_ES11ORTHOX (VPG_ES11 + 102) +#define VPC_ES11PIXELSTOREI (VPG_ES11 + 103) +#define VPC_ES11POINTPARAMETERF (VPG_ES11 + 104) +#define VPC_ES11POINTPARAMETERFV (VPG_ES11 + 105) +#define VPC_ES11POINTPARAMETERX (VPG_ES11 + 106) +#define VPC_ES11POINTPARAMETERXV (VPG_ES11 + 107) +#define VPC_ES11POINTSIZE (VPG_ES11 + 108) +#define VPC_ES11POINTSIZEX (VPG_ES11 + 109) +#define VPC_ES11POLYGONOFFSET (VPG_ES11 + 110) +#define VPC_ES11POLYGONOFFSETX (VPG_ES11 + 111) +#define VPC_ES11POPMATRIX (VPG_ES11 + 112) +#define VPC_ES11PUSHMATRIX (VPG_ES11 + 113) +#define VPC_ES11READPIXELS (VPG_ES11 + 114) +#define VPC_ES11ROTATEF (VPG_ES11 + 115) +#define VPC_ES11ROTATEX (VPG_ES11 + 116) +#define VPC_ES11SAMPLECOVERAGE (VPG_ES11 + 117) +#define VPC_ES11SAMPLECOVERAGEX (VPG_ES11 + 118) +#define VPC_ES11SCALEF (VPG_ES11 + 119) +#define VPC_ES11SCALEX (VPG_ES11 + 120) +#define VPC_ES11SCISSOR (VPG_ES11 + 121) +#define VPC_ES11SHADEMODEL (VPG_ES11 + 122) +#define VPC_ES11STENCILFUNC (VPG_ES11 + 123) +#define VPC_ES11STENCILMASK (VPG_ES11 + 124) +#define VPC_ES11STENCILOP (VPG_ES11 + 125) +#define VPC_ES11TEXCOORDPOINTER (VPG_ES11 + 126) +#define VPC_ES11TEXENVF (VPG_ES11 + 127) +#define VPC_ES11TEXENVFV (VPG_ES11 + 128) +#define VPC_ES11TEXENVI (VPG_ES11 + 129) +#define VPC_ES11TEXENVIV (VPG_ES11 + 130) +#define VPC_ES11TEXENVX (VPG_ES11 + 131) +#define VPC_ES11TEXENVXV (VPG_ES11 + 132) +#define VPC_ES11TEXIMAGE2D (VPG_ES11 + 133) +#define VPC_ES11TEXPARAMETERF (VPG_ES11 + 134) +#define VPC_ES11TEXPARAMETERFV (VPG_ES11 + 135) +#define VPC_ES11TEXPARAMETERI (VPG_ES11 + 136) +#define VPC_ES11TEXPARAMETERIV (VPG_ES11 + 137) +#define VPC_ES11TEXPARAMETERX (VPG_ES11 + 138) +#define VPC_ES11TEXPARAMETERXV (VPG_ES11 + 139) +#define VPC_ES11TEXSUBIMAGE2D (VPG_ES11 + 140) +#define VPC_ES11TRANSLATEF (VPG_ES11 + 141) +#define VPC_ES11TRANSLATEX (VPG_ES11 + 142) +#define VPC_ES11VERTEXPOINTER (VPG_ES11 + 143) +#define VPC_ES11VIEWPORT (VPG_ES11 + 144) +#define VPC_ES11CALLS (VPG_ES11 + 145) +#define VPC_ES11DRAWCALLS (VPG_ES11 + 146) +#define VPC_ES11STATECHANGECALLS (VPG_ES11 + 147) +#define VPC_ES11POINTCOUNT (VPG_ES11 + 148) +#define VPC_ES11LINECOUNT (VPG_ES11 + 149) +#define VPC_ES11TRIANGLECOUNT (VPG_ES11 + 150) + +/* OpenGLES 2.x */ +#define VPC_ES20ACTIVETEXTURE (VPG_ES20 + 1) +#define VPC_ES20ATTACHSHADER (VPG_ES20 + 2) +#define VPC_ES20BINDATTRIBLOCATION (VPG_ES20 + 3) +#define VPC_ES20BINDBUFFER (VPG_ES20 + 4) +#define VPC_ES20BINDFRAMEBUFFER (VPG_ES20 + 5) +#define VPC_ES20BINDRENDERBUFFER (VPG_ES20 + 6) +#define VPC_ES20BINDTEXTURE (VPG_ES20 + 7) +#define VPC_ES20BLENDCOLOR (VPG_ES20 + 8) +#define VPC_ES20BLENDEQUATION (VPG_ES20 + 9) +#define VPC_ES20BLENDEQUATIONSEPARATE (VPG_ES20 + 10) +#define VPC_ES20BLENDFUNC (VPG_ES20 + 11) +#define VPC_ES20BLENDFUNCSEPARATE (VPG_ES20 + 12) +#define VPC_ES20BUFFERDATA (VPG_ES20 + 13) +#define VPC_ES20BUFFERSUBDATA (VPG_ES20 + 14) +#define VPC_ES20CHECKFRAMEBUFFERSTATUS (VPG_ES20 + 15) +#define VPC_ES20CLEAR (VPG_ES20 + 16) +#define VPC_ES20CLEARCOLOR (VPG_ES20 + 17) +#define VPC_ES20CLEARDEPTHF (VPG_ES20 + 18) +#define VPC_ES20CLEARSTENCIL (VPG_ES20 + 19) +#define VPC_ES20COLORMASK (VPG_ES20 + 20) +#define VPC_ES20COMPILESHADER (VPG_ES20 + 21) +#define VPC_ES20COMPRESSEDTEXIMAGE2D (VPG_ES20 + 22) +#define VPC_ES20COMPRESSEDTEXSUBIMAGE2D (VPG_ES20 + 23) +#define VPC_ES20COPYTEXIMAGE2D (VPG_ES20 + 24) +#define VPC_ES20COPYTEXSUBIMAGE2D (VPG_ES20 + 25) +#define VPC_ES20CREATEPROGRAM (VPG_ES20 + 26) +#define VPC_ES20CREATESHADER (VPG_ES20 + 27) +#define VPC_ES20CULLFACE (VPG_ES20 + 28) +#define VPC_ES20DELETEBUFFERS (VPG_ES20 + 29) +#define VPC_ES20DELETEFRAMEBUFFERS (VPG_ES20 + 30) +#define VPC_ES20DELETEPROGRAM (VPG_ES20 + 31) +#define VPC_ES20DELETERENDERBUFFERS (VPG_ES20 + 32) +#define VPC_ES20DELETESHADER (VPG_ES20 + 33) +#define VPC_ES20DELETETEXTURES (VPG_ES20 + 34) +#define VPC_ES20DEPTHFUNC (VPG_ES20 + 35) +#define VPC_ES20DEPTHMASK (VPG_ES20 + 36) +#define VPC_ES20DEPTHRANGEF (VPG_ES20 + 37) +#define VPC_ES20DETACHSHADER (VPG_ES20 + 38) +#define VPC_ES20DISABLE (VPG_ES20 + 39) +#define VPC_ES20DISABLEVERTEXATTRIBARRAY (VPG_ES20 + 40) +#define VPC_ES20DRAWARRAYS (VPG_ES20 + 41) +#define VPC_ES20DRAWELEMENTS (VPG_ES20 + 42) +#define VPC_ES20ENABLE (VPG_ES20 + 43) +#define VPC_ES20ENABLEVERTEXATTRIBARRAY (VPG_ES20 + 44) +#define VPC_ES20FINISH (VPG_ES20 + 45) +#define VPC_ES20FLUSH (VPG_ES20 + 46) +#define VPC_ES20FRAMEBUFFERRENDERBUFFER (VPG_ES20 + 47) +#define VPC_ES20FRAMEBUFFERTEXTURE2D (VPG_ES20 + 48) +#define VPC_ES20FRONTFACE (VPG_ES20 + 49) +#define VPC_ES20GENBUFFERS (VPG_ES20 + 50) +#define VPC_ES20GENERATEMIPMAP (VPG_ES20 + 51) +#define VPC_ES20GENFRAMEBUFFERS (VPG_ES20 + 52) +#define VPC_ES20GENRENDERBUFFERS (VPG_ES20 + 53) +#define VPC_ES20GENTEXTURES (VPG_ES20 + 54) +#define VPC_ES20GETACTIVEATTRIB (VPG_ES20 + 55) +#define VPC_ES20GETACTIVEUNIFORM (VPG_ES20 + 56) +#define VPC_ES20GETATTACHEDSHADERS (VPG_ES20 + 57) +#define VPC_ES20GETATTRIBLOCATION (VPG_ES20 + 58) +#define VPC_ES20GETBOOLEANV (VPG_ES20 + 59) +#define VPC_ES20GETBUFFERPARAMETERIV (VPG_ES20 + 60) +#define VPC_ES20GETERROR (VPG_ES20 + 61) +#define VPC_ES20GETFLOATV (VPG_ES20 + 62) +#define VPC_ES20GETFRAMEBUFFERATTACHMENTPARAMETERIV (VPG_ES20 + 63) +#define VPC_ES20GETINTEGERV (VPG_ES20 + 64) +#define VPC_ES20GETPROGRAMIV (VPG_ES20 + 65) +#define VPC_ES20GETPROGRAMINFOLOG (VPG_ES20 + 66) +#define VPC_ES20GETRENDERBUFFERPARAMETERIV (VPG_ES20 + 67) +#define VPC_ES20GETSHADERIV (VPG_ES20 + 68) +#define VPC_ES20GETSHADERINFOLOG (VPG_ES20 + 69) +#define VPC_ES20GETSHADERPRECISIONFORMAT (VPG_ES20 + 70) +#define VPC_ES20GETSHADERSOURCE (VPG_ES20 + 71) +#define VPC_ES20GETSTRING (VPG_ES20 + 72) +#define VPC_ES20GETTEXPARAMETERFV (VPG_ES20 + 73) +#define VPC_ES20GETTEXPARAMETERIV (VPG_ES20 + 74) +#define VPC_ES20GETUNIFORMFV (VPG_ES20 + 75) +#define VPC_ES20GETUNIFORMIV (VPG_ES20 + 76) +#define VPC_ES20GETUNIFORMLOCATION (VPG_ES20 + 77) +#define VPC_ES20GETVERTEXATTRIBFV (VPG_ES20 + 78) +#define VPC_ES20GETVERTEXATTRIBIV (VPG_ES20 + 79) +#define VPC_ES20GETVERTEXATTRIBPOINTERV (VPG_ES20 + 80) +#define VPC_ES20HINT (VPG_ES20 + 81) +#define VPC_ES20ISBUFFER (VPG_ES20 + 82) +#define VPC_ES20ISENABLED (VPG_ES20 + 83) +#define VPC_ES20ISFRAMEBUFFER (VPG_ES20 + 84) +#define VPC_ES20ISPROGRAM (VPG_ES20 + 85) +#define VPC_ES20ISRENDERBUFFER (VPG_ES20 + 86) +#define VPC_ES20ISSHADER (VPG_ES20 + 87) +#define VPC_ES20ISTEXTURE (VPG_ES20 + 88) +#define VPC_ES20LINEWIDTH (VPG_ES20 + 89) +#define VPC_ES20LINKPROGRAM (VPG_ES20 + 90) +#define VPC_ES20PIXELSTOREI (VPG_ES20 + 91) +#define VPC_ES20POLYGONOFFSET (VPG_ES20 + 92) +#define VPC_ES20READPIXELS (VPG_ES20 + 93) +#define VPC_ES20RELEASESHADERCOMPILER (VPG_ES20 + 94) +#define VPC_ES20RENDERBUFFERSTORAGE (VPG_ES20 + 95) +#define VPC_ES20SAMPLECOVERAGE (VPG_ES20 + 96) +#define VPC_ES20SCISSOR (VPG_ES20 + 97) +#define VPC_ES20SHADERBINARY (VPG_ES20 + 98) +#define VPC_ES20SHADERSOURCE (VPG_ES20 + 99) +#define VPC_ES20STENCILFUNC (VPG_ES20 + 100) +#define VPC_ES20STENCILFUNCSEPARATE (VPG_ES20 + 101) +#define VPC_ES20STENCILMASK (VPG_ES20 + 102) +#define VPC_ES20STENCILMASKSEPARATE (VPG_ES20 + 103) +#define VPC_ES20STENCILOP (VPG_ES20 + 104) +#define VPC_ES20STENCILOPSEPARATE (VPG_ES20 + 105) +#define VPC_ES20TEXIMAGE2D (VPG_ES20 + 106) +#define VPC_ES20TEXPARAMETERF (VPG_ES20 + 107) +#define VPC_ES20TEXPARAMETERFV (VPG_ES20 + 108) +#define VPC_ES20TEXPARAMETERI (VPG_ES20 + 109) +#define VPC_ES20TEXPARAMETERIV (VPG_ES20 + 110) +#define VPC_ES20TEXSUBIMAGE2D (VPG_ES20 + 111) +#define VPC_ES20UNIFORM1F (VPG_ES20 + 112) +#define VPC_ES20UNIFORM1FV (VPG_ES20 + 113) +#define VPC_ES20UNIFORM1I (VPG_ES20 + 114) +#define VPC_ES20UNIFORM1IV (VPG_ES20 + 115) +#define VPC_ES20UNIFORM2F (VPG_ES20 + 116) +#define VPC_ES20UNIFORM2FV (VPG_ES20 + 117) +#define VPC_ES20UNIFORM2I (VPG_ES20 + 118) +#define VPC_ES20UNIFORM2IV (VPG_ES20 + 119) +#define VPC_ES20UNIFORM3F (VPG_ES20 + 120) +#define VPC_ES20UNIFORM3FV (VPG_ES20 + 121) +#define VPC_ES20UNIFORM3I (VPG_ES20 + 122) +#define VPC_ES20UNIFORM3IV (VPG_ES20 + 123) +#define VPC_ES20UNIFORM4F (VPG_ES20 + 124) +#define VPC_ES20UNIFORM4FV (VPG_ES20 + 125) +#define VPC_ES20UNIFORM4I (VPG_ES20 + 126) +#define VPC_ES20UNIFORM4IV (VPG_ES20 + 127) +#define VPC_ES20UNIFORMMATRIX2FV (VPG_ES20 + 128) +#define VPC_ES20UNIFORMMATRIX3FV (VPG_ES20 + 129) +#define VPC_ES20UNIFORMMATRIX4FV (VPG_ES20 + 130) +#define VPC_ES20USEPROGRAM (VPG_ES20 + 131) +#define VPC_ES20VALIDATEPROGRAM (VPG_ES20 + 132) +#define VPC_ES20VERTEXATTRIB1F (VPG_ES20 + 133) +#define VPC_ES20VERTEXATTRIB1FV (VPG_ES20 + 134) +#define VPC_ES20VERTEXATTRIB2F (VPG_ES20 + 135) +#define VPC_ES20VERTEXATTRIB2FV (VPG_ES20 + 136) +#define VPC_ES20VERTEXATTRIB3F (VPG_ES20 + 137) +#define VPC_ES20VERTEXATTRIB3FV (VPG_ES20 + 138) +#define VPC_ES20VERTEXATTRIB4F (VPG_ES20 + 139) +#define VPC_ES20VERTEXATTRIB4FV (VPG_ES20 + 140) +#define VPC_ES20VERTEXATTRIBPOINTER (VPG_ES20 + 141) +#define VPC_ES20VIEWPORT (VPG_ES20 + 142) +#define VPC_ES20CALLS (VPG_ES20 + 143) +#define VPC_ES20DRAWCALLS (VPG_ES20 + 144) +#define VPC_ES20STATECHANGECALLS (VPG_ES20 + 145) +#define VPC_ES20POINTCOUNT (VPG_ES20 + 146) +#define VPC_ES20LINECOUNT (VPG_ES20 + 147) +#define VPC_ES20TRIANGLECOUNT (VPG_ES20 + 148) + +/* VG11 Counters. */ +#define VPC_VG11APPENDPATH (VPG_VG11 + 1) +#define VPC_VG11APPENDPATHDATA (VPG_VG11 + 2) +#define VPC_VG11CHILDIMAGE (VPG_VG11 + 3) +#define VPC_VG11CLEAR (VPG_VG11 + 4) +#define VPC_VG11CLEARGLYPH (VPG_VG11 + 5) +#define VPC_VG11CLEARIMAGE (VPG_VG11 + 6) +#define VPC_VG11CLEARPATH (VPG_VG11 + 7) +#define VPC_VG11COLORMATRIX (VPG_VG11 + 8) +#define VPC_VG11CONVOLVE (VPG_VG11 + 9) +#define VPC_VG11COPYIMAGE (VPG_VG11 + 10) +#define VPC_VG11COPYMASK (VPG_VG11 + 11) +#define VPC_VG11COPYPIXELS (VPG_VG11 + 12) +#define VPC_VG11CREATEFONT (VPG_VG11 + 13) +#define VPC_VG11CREATEIMAGE (VPG_VG11 + 14) +#define VPC_VG11CREATEMASKLAYER (VPG_VG11 + 15) +#define VPC_VG11CREATEPAINT (VPG_VG11 + 16) +#define VPC_VG11CREATEPATH (VPG_VG11 + 17) +#define VPC_VG11DESTROYFONT (VPG_VG11 + 18) +#define VPC_VG11DESTROYIMAGE (VPG_VG11 + 19) +#define VPC_VG11DESTROYMASKLAYER (VPG_VG11 + 20) +#define VPC_VG11DESTROYPAINT (VPG_VG11 + 21) +#define VPC_VG11DESTROYPATH (VPG_VG11 + 22) +#define VPC_VG11DRAWGLYPH (VPG_VG11 + 23) +#define VPC_VG11DRAWGLYPHS (VPG_VG11 + 24) +#define VPC_VG11DRAWIMAGE (VPG_VG11 + 25) +#define VPC_VG11DRAWPATH (VPG_VG11 + 26) +#define VPC_VG11FILLMASKLAYER (VPG_VG11 + 27) +#define VPC_VG11FINISH (VPG_VG11 + 28) +#define VPC_VG11FLUSH (VPG_VG11 + 29) +#define VPC_VG11GAUSSIANBLUR (VPG_VG11 + 30) +#define VPC_VG11GETCOLOR (VPG_VG11 + 31) +#define VPC_VG11GETERROR (VPG_VG11 + 32) +#define VPC_VG11GETF (VPG_VG11 + 33) +#define VPC_VG11GETFV (VPG_VG11 + 34) +#define VPC_VG11GETI (VPG_VG11 + 35) +#define VPC_VG11GETIMAGESUBDATA (VPG_VG11 + 36) +#define VPC_VG11GETIV (VPG_VG11 + 37) +#define VPC_VG11GETMATRIX (VPG_VG11 + 38) +#define VPC_VG11GETPAINT (VPG_VG11 + 39) +#define VPC_VG11GETPARAMETERF (VPG_VG11 + 40) +#define VPC_VG11GETPARAMETERFV (VPG_VG11 + 41) +#define VPC_VG11GETPARAMETERI (VPG_VG11 + 42) +#define VPC_VG11GETPARAMETERIV (VPG_VG11 + 43) +#define VPC_VG11GETPARAMETERVECTORSIZE (VPG_VG11 + 44) +#define VPC_VG11GETPARENT (VPG_VG11 + 45) +#define VPC_VG11GETPATHCAPABILITIES (VPG_VG11 + 46) +#define VPC_VG11GETPIXELS (VPG_VG11 + 47) +#define VPC_VG11GETSTRING (VPG_VG11 + 48) +#define VPC_VG11GETVECTORSIZE (VPG_VG11 + 49) +#define VPC_VG11HARDWAREQUERY (VPG_VG11 + 50) +#define VPC_VG11IMAGESUBDATA (VPG_VG11 + 51) +#define VPC_VG11INTERPOLATEPATH (VPG_VG11 + 52) +#define VPC_VG11LOADIDENTITY (VPG_VG11 + 53) +#define VPC_VG11LOADMATRIX (VPG_VG11 + 54) +#define VPC_VG11LOOKUP (VPG_VG11 + 55) +#define VPC_VG11LOOKUPSINGLE (VPG_VG11 + 56) +#define VPC_VG11MASK (VPG_VG11 + 57) +#define VPC_VG11MODIFYPATHCOORDS (VPG_VG11 + 58) +#define VPC_VG11MULTMATRIX (VPG_VG11 + 59) +#define VPC_VG11PAINTPATTERN (VPG_VG11 + 60) +#define VPC_VG11PATHBOUNDS (VPG_VG11 + 61) +#define VPC_VG11PATHLENGTH (VPG_VG11 + 62) +#define VPC_VG11PATHTRANSFORMEDBOUNDS (VPG_VG11 + 63) +#define VPC_VG11POINTALONGPATH (VPG_VG11 + 64) +#define VPC_VG11READPIXELS (VPG_VG11 + 65) +#define VPC_VG11REMOVEPATHCAPABILITIES (VPG_VG11 + 66) +#define VPC_VG11RENDERTOMASK (VPG_VG11 + 67) +#define VPC_VG11ROTATE (VPG_VG11 + 68) +#define VPC_VG11SCALE (VPG_VG11 + 69) +#define VPC_VG11SEPARABLECONVOLVE (VPG_VG11 + 70) +#define VPC_VG11SETCOLOR (VPG_VG11 + 71) +#define VPC_VG11SETF (VPG_VG11 + 72) +#define VPC_VG11SETFV (VPG_VG11 + 73) +#define VPC_VG11SETGLYPHTOIMAGE (VPG_VG11 + 74) +#define VPC_VG11SETGLYPHTOPATH (VPG_VG11 + 75) +#define VPC_VG11SETI (VPG_VG11 + 76) +#define VPC_VG11SETIV (VPG_VG11 + 77) +#define VPC_VG11SETPAINT (VPG_VG11 + 78) +#define VPC_VG11SETPARAMETERF (VPG_VG11 + 79) +#define VPC_VG11SETPARAMETERFV (VPG_VG11 + 80) +#define VPC_VG11SETPARAMETERI (VPG_VG11 + 81) +#define VPC_VG11SETPARAMETERIV (VPG_VG11 + 82) +#define VPC_VG11SETPIXELS (VPG_VG11 + 83) +#define VPC_VG11SHEAR (VPG_VG11 + 84) +#define VPC_VG11TRANSFORMPATH (VPG_VG11 + 85) +#define VPC_VG11TRANSLATE (VPG_VG11 + 86) +#define VPC_VG11WRITEPIXELS (VPG_VG11 + 87) +#define VPC_VG11CALLS (VPG_VG11 + 88) +#define VPC_VG11DRAWCALLS (VPG_VG11 + 89) +#define VPC_VG11STATECHANGECALLS (VPG_VG11 + 90) +#define VPC_VG11FILLCOUNT (VPG_VG11 + 91) +#define VPC_VG11STROKECOUNT (VPG_VG11 + 92) + +/* HAL Counters. */ +#define VPC_HALVERTBUFNEWBYTEALLOC (VPG_HAL + 1) +#define VPC_HALVERTBUFTOTALBYTEALLOC (VPG_HAL + 2) +#define VPC_HALVERTBUFNEWOBJALLOC (VPG_HAL + 3) +#define VPC_HALVERTBUFTOTALOBJALLOC (VPG_HAL + 4) +#define VPC_HALINDBUFNEWBYTEALLOC (VPG_HAL + 5) +#define VPC_HALINDBUFTOTALBYTEALLOC (VPG_HAL + 6) +#define VPC_HALINDBUFNEWOBJALLOC (VPG_HAL + 7) +#define VPC_HALINDBUFTOTALOBJALLOC (VPG_HAL + 8) +#define VPC_HALTEXBUFNEWBYTEALLOC (VPG_HAL + 9) +#define VPC_HALTEXBUFTOTALBYTEALLOC (VPG_HAL + 10) +#define VPC_HALTEXBUFNEWOBJALLOC (VPG_HAL + 11) +#define VPC_HALTEXBUFTOTALOBJALLOC (VPG_HAL + 12) + +#define VPC_VG11TRANSLATE (VPG_VG11 + 86) +#define VPC_VG11WRITEPIXELS (VPG_VG11 + 87) +#define VPC_VG11CALLS (VPG_VG11 + 88) +#define VPC_VG11DRAWCALLS (VPG_VG11 + 89) +#define VPC_VG11STATECHANGECALLS (VPG_VG11 + 90) +#define VPC_VG11FILLCOUNT (VPG_VG11 + 91) +#define VPC_VG11STROKECOUNT (VPG_VG11 + 92) + +/* HAL Counters. */ +#define VPC_HALVERTBUFNEWBYTEALLOC (VPG_HAL + 1) +#define VPC_HALVERTBUFTOTALBYTEALLOC (VPG_HAL + 2) +#define VPC_HALVERTBUFNEWOBJALLOC (VPG_HAL + 3) +#define VPC_HALVERTBUFTOTALOBJALLOC (VPG_HAL + 4) +#define VPC_HALINDBUFNEWBYTEALLOC (VPG_HAL + 5) +#define VPC_HALINDBUFTOTALBYTEALLOC (VPG_HAL + 6) +#define VPC_HALINDBUFNEWOBJALLOC (VPG_HAL + 7) +#define VPC_HALINDBUFTOTALOBJALLOC (VPG_HAL + 8) +#define VPC_HALTEXBUFNEWBYTEALLOC (VPG_HAL + 9) +#define VPC_HALTEXBUFTOTALBYTEALLOC (VPG_HAL + 10) +#define VPC_HALTEXBUFNEWOBJALLOC (VPG_HAL + 11) +#define VPC_HALTEXBUFTOTALOBJALLOC (VPG_HAL + 12) + +/* HW: GPU Counters. */ +#define VPC_GPUCYCLES (VPG_GPU + 1) +#define VPC_GPUREAD64BYTE (VPG_GPU + 2) +#define VPC_GPUWRITE64BYTE (VPG_GPU + 3) + +/* HW: Shader Counters. */ +#define VPC_VSINSTCOUNT (VPG_VS + 1) +#define VPC_VSBRANCHINSTCOUNT (VPG_VS + 2) +#define VPC_VSTEXLDINSTCOUNT (VPG_VS + 3) +#define VPC_VSRENDEREDVERTCOUNT (VPG_VS + 4) +/* HW: PS Count. */ +#define VPC_PSINSTCOUNT (VPG_PS + 1) +#define VPC_PSBRANCHINSTCOUNT (VPG_PS + 2) +#define VPC_PSTEXLDINSTCOUNT (VPG_PS + 3) +#define VPC_PSRENDEREDPIXCOUNT (VPG_PS + 4) + + +/* HW: PA Counters. */ +#define VPC_PAINVERTCOUNT (VPG_PA + 1) +#define VPC_PAINPRIMCOUNT (VPG_PA + 2) +#define VPC_PAOUTPRIMCOUNT (VPG_PA + 3) +#define VPC_PADEPTHCLIPCOUNT (VPG_PA + 4) +#define VPC_PATRIVIALREJCOUNT (VPG_PA + 5) +#define VPC_PACULLCOUNT (VPG_PA + 6) + +/* HW: Setup Counters. */ +#define VPC_SETRIANGLECOUNT (VPG_SETUP + 1) +#define VPC_SELINECOUNT (VPG_SETUP + 2) + +/* HW: RA Counters. */ +#define VPC_RAVALIDPIXCOUNT (VPG_RA + 1) +#define VPC_RATOTALQUADCOUNT (VPG_RA + 2) +#define VPC_RAVALIDQUADCOUNTEZ (VPG_RA + 3) +#define VPC_RATOTALPRIMCOUNT (VPG_RA + 4) +#define VPC_RAPIPECACHEMISSCOUNT (VPG_RA + 5) +#define VPC_RAPREFCACHEMISSCOUNT (VPG_RA + 6) +#define VPC_RAEEZCULLCOUNT (VPG_RA + 7) + +/* HW: TEX Counters. */ +#define VPC_TXTOTBILINEARREQ (VPG_TX + 1) +#define VPC_TXTOTTRILINEARREQ (VPG_TX + 2) +#define VPC_TXTOTDISCARDTEXREQ (VPG_TX + 3) +#define VPC_TXTOTTEXREQ (VPG_TX + 4) +#define VPC_TXMEMREADCOUNT (VPG_TX + 5) +#define VPC_TXMEMREADIN8BCOUNT (VPG_TX + 6) +#define VPC_TXCACHEMISSCOUNT (VPG_TX + 7) +#define VPC_TXCACHEHITTEXELCOUNT (VPG_TX + 8) +#define VPC_TXCACHEMISSTEXELCOUNT (VPG_TX + 9) + +/* HW: PE Counters. */ +#define VPC_PEKILLEDBYCOLOR (VPG_PE + 1) +#define VPC_PEKILLEDBYDEPTH (VPG_PE + 2) +#define VPC_PEDRAWNBYCOLOR (VPG_PE + 3) +#define VPC_PEDRAWNBYDEPTH (VPG_PE + 4) + +/* HW: MC Counters. */ +#define VPC_MCREADREQ8BPIPE (VPG_MC + 1) +#define VPC_MCREADREQ8BIP (VPG_MC + 2) +#define VPC_MCWRITEREQ8BPIPE (VPG_MC + 3) + +/* HW: AXI Counters. */ +#define VPC_AXIREADREQSTALLED (VPG_AXI + 1) +#define VPC_AXIWRITEREQSTALLED (VPG_AXI + 2) +#define VPC_AXIWRITEDATASTALLED (VPG_AXI + 3) + +/* PROGRAM: Shader program counters. */ +#define VPC_PVSINSTRCOUNT (VPG_PVS + 1) +#define VPC_PVSALUINSTRCOUNT (VPG_PVS + 2) +#define VPC_PVSTEXINSTRCOUNT (VPG_PVS + 3) +#define VPC_PVSATTRIBCOUNT (VPG_PVS + 4) +#define VPC_PVSUNIFORMCOUNT (VPG_PVS + 5) +#define VPC_PVSFUNCTIONCOUNT (VPG_PVS + 6) + +#define VPC_PPSINSTRCOUNT (VPG_PPS + 1) +#define VPC_PPSALUINSTRCOUNT (VPG_PPS + 2) +#define VPC_PPSTEXINSTRCOUNT (VPG_PPS + 3) +#define VPC_PPSATTRIBCOUNT (VPG_PPS + 4) +#define VPC_PPSUNIFORMCOUNT (VPG_PPS + 5) +#define VPC_PPSFUNCTIONCOUNT (VPG_PPS + 6) + +#endif + + +/* HW profile information. */ +typedef struct _gcsPROFILER_COUNTERS +{ + /* HW static counters. */ + gctUINT32 gpuClock; + gctUINT32 axiClock; + gctUINT32 shaderClock; + + /* HW vairable counters. */ + gctUINT32 gpuClockStart; + gctUINT32 gpuClockEnd; + + /* HW vairable counters. */ + gctUINT32 gpuCyclesCounter; + gctUINT32 gpuTotalRead64BytesPerFrame; + gctUINT32 gpuTotalWrite64BytesPerFrame; + + /* PE */ + gctUINT32 pe_pixel_count_killed_by_color_pipe; + gctUINT32 pe_pixel_count_killed_by_depth_pipe; + gctUINT32 pe_pixel_count_drawn_by_color_pipe; + gctUINT32 pe_pixel_count_drawn_by_depth_pipe; + + /* SH */ + gctUINT32 ps_inst_counter; + gctUINT32 rendered_pixel_counter; + gctUINT32 vs_inst_counter; + gctUINT32 rendered_vertice_counter; + gctUINT32 vtx_branch_inst_counter; + gctUINT32 vtx_texld_inst_counter; + gctUINT32 pxl_branch_inst_counter; + gctUINT32 pxl_texld_inst_counter; + + /* PA */ + gctUINT32 pa_input_vtx_counter; + gctUINT32 pa_input_prim_counter; + gctUINT32 pa_output_prim_counter; + gctUINT32 pa_depth_clipped_counter; + gctUINT32 pa_trivial_rejected_counter; + gctUINT32 pa_culled_counter; + + /* SE */ + gctUINT32 se_culled_triangle_count; + gctUINT32 se_culled_lines_count; + + /* RA */ + gctUINT32 ra_valid_pixel_count; + gctUINT32 ra_total_quad_count; + gctUINT32 ra_valid_quad_count_after_early_z; + gctUINT32 ra_total_primitive_count; + gctUINT32 ra_pipe_cache_miss_counter; + gctUINT32 ra_prefetch_cache_miss_counter; + gctUINT32 ra_eez_culled_counter; + + /* TX */ + gctUINT32 tx_total_bilinear_requests; + gctUINT32 tx_total_trilinear_requests; + gctUINT32 tx_total_discarded_texture_requests; + gctUINT32 tx_total_texture_requests; + gctUINT32 tx_mem_read_count; + gctUINT32 tx_mem_read_in_8B_count; + gctUINT32 tx_cache_miss_count; + gctUINT32 tx_cache_hit_texel_count; + gctUINT32 tx_cache_miss_texel_count; + + /* MC */ + gctUINT32 mc_total_read_req_8B_from_pipeline; + gctUINT32 mc_total_read_req_8B_from_IP; + gctUINT32 mc_total_write_req_8B_from_pipeline; + + /* HI */ + gctUINT32 hi_axi_cycles_read_request_stalled; + gctUINT32 hi_axi_cycles_write_request_stalled; + gctUINT32 hi_axi_cycles_write_data_stalled; +} +gcsPROFILER_COUNTERS; + +/* HAL profile information. */ +typedef struct _gcsPROFILER +{ + gctUINT32 enable; + gctBOOL enableHal; + gctBOOL enableHW; + gctBOOL enableSH; + + gctBOOL useSocket; + gctINT sockFd; + + gctFILE file; + + /* Aggregate Information */ + + /* Clock Info */ + gctUINT64 frameStart; + gctUINT64 frameEnd; + + /* Current frame information */ + gctUINT32 frameNumber; + gctUINT64 frameStartTimeusec; + gctUINT64 frameEndTimeusec; + gctUINT64 frameStartCPUTimeusec; + gctUINT64 frameEndCPUTimeusec; + +/* #if PROFILE_HAL_COUNTERS */ + gctUINT32 vertexBufferTotalBytesAlloc; + gctUINT32 vertexBufferNewBytesAlloc; + int vertexBufferTotalObjectsAlloc; + int vertexBufferNewObjectsAlloc; + + gctUINT32 indexBufferTotalBytesAlloc; + gctUINT32 indexBufferNewBytesAlloc; + int indexBufferTotalObjectsAlloc; + int indexBufferNewObjectsAlloc; + + gctUINT32 textureBufferTotalBytesAlloc; + gctUINT32 textureBufferNewBytesAlloc; + int textureBufferTotalObjectsAlloc; + int textureBufferNewObjectsAlloc; + + gctUINT32 numCommits; + gctUINT32 drawPointCount; + gctUINT32 drawLineCount; + gctUINT32 drawTriangleCount; + gctUINT32 drawVertexCount; + gctUINT32 redundantStateChangeCalls; +/* #endif */ +} +gcsPROFILER; + +/* Memory profile information. */ +struct _gcsMemProfile +{ + /* Memory Usage */ + gctUINT32 videoMemUsed; + gctUINT32 systemMemUsed; + gctUINT32 commitBufferSize; + gctUINT32 contextBufferCopyBytes; +}; + +/* Shader profile information. */ +struct _gcsSHADER_PROFILER +{ + gctUINT32 shaderLength; + gctUINT32 shaderALUCycles; + gctUINT32 shaderTexLoadCycles; + gctUINT32 shaderTempRegCount; + gctUINT32 shaderSamplerRegCount; + gctUINT32 shaderInputRegCount; + gctUINT32 shaderOutputRegCount; +}; + +/* Initialize the gcsProfiler. */ +gceSTATUS +gcoPROFILER_Initialize( + IN gcoHAL Hal + ); + +/* Destroy the gcProfiler. */ +gceSTATUS +gcoPROFILER_Destroy( + IN gcoHAL Hal + ); + +/* Write data to profiler. */ +gceSTATUS +gcoPROFILER_Write( + IN gcoHAL Hal, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Flush data out. */ +gceSTATUS +gcoPROFILER_Flush( + IN gcoHAL Hal + ); + +/* Call to signal end of frame. */ +gceSTATUS +gcoPROFILER_EndFrame( + IN gcoHAL Hal + ); + +/* Increase profile counter Enum by Value. */ +gceSTATUS +gcoPROFILER_Count( + IN gcoHAL Hal, + IN gctUINT32 Enum, + IN gctINT Value + ); + +/* Profile input vertex shader. */ +gceSTATUS +gcoPROFILER_ShaderVS( + IN gcoHAL Hal, + IN gctPOINTER Vs + ); + +/* Profile input fragment shader. */ +gceSTATUS +gcoPROFILER_ShaderFS( + IN gcoHAL Hal, + IN gctPOINTER Fs + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_profiler_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_raster.h b/kernel_drivers/v2/hal/inc/gc_hal_raster.h new file mode 100644 index 0000000..4f1d374 --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_raster.h @@ -0,0 +1,842 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_raster_h_ +#define __gc_hal_raster_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoBRUSH * gcoBRUSH; +typedef struct _gcoBRUSH_CACHE * gcoBRUSH_CACHE; + +/******************************************************************************\ +******************************** gcoBRUSH Object ******************************* +\******************************************************************************/ + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructSingleColor( + IN gcoHAL Hal, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructMonochrome( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructColor( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Destroy an gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_Destroy( + IN gcoBRUSH Brush + ); + +/******************************************************************************\ +******************************** gcoSURF Object ******************************* +\******************************************************************************/ + +/* Set cipping rectangle. */ +gceSTATUS +gcoSURF_SetClipping( + IN gcoSURF Surface + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gcoSURF_Clear2D( + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN gcsRECT_PTR DestRect, + IN gctUINT32 LoColor, + IN gctUINT32 HiColor + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gcoSURF_Line( + IN gcoSURF Surface, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop + ); + +/* Generic rectangular blit. */ +gceSTATUS +gcoSURF_Blit( + IN OPTIONAL gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN OPTIONAL gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN OPTIONAL gceSURF_TRANSPARENCY Transparency, + IN OPTIONAL gctUINT32 TransparencyColor, + IN OPTIONAL gctPOINTER Mask, + IN OPTIONAL gceSURF_MONOPACK MaskPack + ); + +/* Monochrome blit. */ +gceSTATUS +gcoSURF_MonoBlit( + IN gcoSURF DestSurface, + IN gctPOINTER Source, + IN gceSURF_MONOPACK SourcePack, + IN gcsPOINT_PTR SourceSize, + IN gcsPOINT_PTR SourceOrigin, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Filter blit. */ +gceSTATUS +gcoSURF_FilterBlit( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gcoSURF_EnableAlphaBlend( + IN gcoSURF Surface, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gcoSURF_DisableAlphaBlend( + IN gcoSURF Surface + ); + +/* Copy a rectangular area with format conversion. */ +gceSTATUS +gcoSURF_CopyPixels( + IN gcoSURF Source, + IN gcoSURF Target, + IN gctINT SourceX, + IN gctINT SourceY, + IN gctINT TargetX, + IN gctINT TargetY, + IN gctINT Width, + IN gctINT Height + ); + +/* Read surface pixel. */ +gceSTATUS +gcoSURF_ReadPixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + OUT gctPOINTER PixelValue + ); + +/* Write surface pixel. */ +gceSTATUS +gcoSURF_WritePixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + IN gctPOINTER PixelValue + ); + +/******************************************************************************\ +********************************** gco2D Object ********************************* +\******************************************************************************/ + +/* Construct a new gco2D object. */ +gceSTATUS +gco2D_Construct( + IN gcoHAL Hal, + OUT gco2D * Hardware + ); + +/* Destroy an gco2D object. */ +gceSTATUS +gco2D_Destroy( + IN gco2D Hardware + ); + +/* Sets the maximum number of brushes in the brush cache. */ +gceSTATUS +gco2D_SetBrushLimit( + IN gco2D Hardware, + IN gctUINT MaxCount + ); + +/* Flush the brush. */ +gceSTATUS +gco2D_FlushBrush( + IN gco2D Engine, + IN gcoBRUSH Brush, + IN gceSURF_FORMAT Format + ); + +/* Program the specified solid color brush. */ +gceSTATUS +gco2D_LoadSolidBrush( + IN gco2D Engine, + IN gceSURF_FORMAT Format, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask + ); + +/* Configure monochrome source. */ +gceSTATUS +gco2D_SetMonochromeSource( + IN gco2D Engine, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_MONOPACK DataPack, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source extension for full rotation. */ +gceSTATUS +gco2D_SetColorSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSourceAdvanced( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative + ); + +/* Configure masked color source. */ +gceSTATUS +gco2D_SetMaskedSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack + ); + +/* Configure masked color source extension for full rotation. */ +gceSTATUS +gco2D_SetMaskedSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Setup the source rectangle. */ +gceSTATUS +gco2D_SetSource( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect + ); + +/* Set clipping rectangle. */ +gceSTATUS +gco2D_SetClipping( + IN gco2D Engine, + IN gcsRECT_PTR Rect + ); + +/* Configure destination. */ +gceSTATUS +gco2D_SetTarget( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth + ); + +/* Configure destination extension for full rotation. */ +gceSTATUS +gco2D_SetTargetEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Calculate and program the stretch factors. */ +gceSTATUS +gco2D_SetStretchFactors( + IN gco2D Engine, + IN gctUINT32 HorFactor, + IN gctUINT32 VerFactor + ); + +/* Calculate and program the stretch factors based on the rectangles. */ +gceSTATUS +gco2D_SetStretchRectFactors( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect + ); + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructSingleColorBrush( + IN gco2D Engine, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructMonochromeBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructColorBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gco2D_Clear( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gco2D_Line( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines based on the 32-bit color. */ +gceSTATUS +gco2D_ColorLine( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Generic blit. */ +gceSTATUS +gco2D_Blit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Batch blit. */ +gceSTATUS +gco2D_BatchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Stretch blit. */ +gceSTATUS +gco2D_StretchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Monochrome blit. */ +gceSTATUS +gco2D_MonoBlit( + IN gco2D Engine, + IN gctPOINTER StreamBits, + IN gcsPOINT_PTR StreamSize, + IN gcsRECT_PTR StreamRect, + IN gceSURF_MONOPACK SrcStreamPack, + IN gceSURF_MONOPACK DestStreamPack, + IN gcsRECT_PTR DestRect, + IN gctUINT32 FgRop, + IN gctUINT32 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Set kernel size. */ +gceSTATUS +gco2D_SetKernelSize( + IN gco2D Engine, + IN gctUINT8 HorKernelSize, + IN gctUINT8 VerKernelSize + ); + +/* Set filter type. */ +gceSTATUS +gco2D_SetFilterType( + IN gco2D Engine, + IN gceFILTER_TYPE FilterType + ); + +/* Set the filter kernel by user. */ +gceSTATUS +gco2D_SetUserFilterKernel( + IN gco2D Engine, + IN gceFILTER_PASS_TYPE PassType, + IN gctUINT16_PTR KernelArray + ); + +/* Select the pass(es) to be done for user defined filter. */ +gceSTATUS +gco2D_EnableUserFilterPasses( + IN gco2D Engine, + IN gctBOOL HorPass, + IN gctBOOL VerPass + ); + +/* Frees the temporary buffer allocated by filter blit operation. */ +gceSTATUS +gco2D_FreeFilterBuffer( + IN gco2D Engine + ); + +/* Filter blit. */ +gceSTATUS +gco2D_FilterBlit( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Filter blit extension for full rotation. */ +gceSTATUS +gco2D_FilterBlitEx( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gctUINT32 SrcSurfaceHeight, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gctUINT32 DestSurfaceHeight, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +gceSTATUS +gco2D_FilterBlitEx2( + IN gco2D Engine, + IN gctUINT32_PTR SrcAddresses, + IN gctUINT32 SrcAddressNum, + IN gctUINT32_PTR SrcStrides, + IN gctUINT32 SrcStrideNum, + IN gceTILING SrcTiling, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gctUINT32 SrcSurfaceHeight, + IN gcsRECT_PTR SrcRect, + IN gctUINT32_PTR DestAddresses, + IN gctUINT32 DestAddressNum, + IN gctUINT32_PTR DestStrides, + IN gctUINT32 DestStrideNum, + IN gceTILING DestTiling, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gctUINT32 DestSurfaceHeight, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gco2D_EnableAlphaBlend( + IN gco2D Engine, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Enable alpha blending engine in the hardware. */ +gceSTATUS +gco2D_EnableAlphaBlendAdvanced( + IN gco2D Engine, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode + ); + +/* Enable alpha blending engine with Porter Duff rule. */ +gceSTATUS +gco2D_SetPorterDuffBlending( + IN gco2D Engine, + IN gce2D_PORTER_DUFF_RULE Rule + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gco2D_DisableAlphaBlend( + IN gco2D Engine + ); + +/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */ +gctUINT32 +gco2D_GetMaximumDataCount( + void + ); + +/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */ +gctUINT32 +gco2D_GetMaximumRectCount( + void + ); + +/* Returns the pixel alignment of the surface. */ +gceSTATUS +gco2D_GetPixelAlignment( + gceSURF_FORMAT Format, + gcsPOINT_PTR Alignment + ); + +/* Retrieve monochrome stream pack size. */ +gceSTATUS +gco2D_GetPackSize( + IN gceSURF_MONOPACK StreamPack, + OUT gctUINT32 * PackWidth, + OUT gctUINT32 * PackHeight + ); + +/* Flush the 2D pipeline. */ +gceSTATUS +gco2D_Flush( + IN gco2D Engine + ); + +/* Load 256-entry color table for INDEX8 source surfaces. */ +gceSTATUS +gco2D_LoadPalette( + IN gco2D Engine, + IN gctUINT FirstIndex, + IN gctUINT IndexCount, + IN gctPOINTER ColorTable, + IN gctBOOL ColorConvert + ); + +/* Enable/disable 2D BitBlt mirrorring. */ +gceSTATUS +gco2D_SetBitBlitMirror( + IN gco2D Engine, + IN gctBOOL HorizontalMirror, + IN gctBOOL VerticalMirror + ); + +/* Set the transparency for source, destination and pattern. */ +gceSTATUS +gco2D_SetTransparencyAdvanced( + IN gco2D Engine, + IN gce2D_TRANSPARENCY SrcTransparency, + IN gce2D_TRANSPARENCY DstTransparency, + IN gce2D_TRANSPARENCY PatTransparency + ); + +/* Set the source color key. */ +gceSTATUS +gco2D_SetSourceColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the source color key range. */ +gceSTATUS +gco2D_SetSourceColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the target color key. */ +gceSTATUS +gco2D_SetTargetColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the target color key range. */ +gceSTATUS +gco2D_SetTargetColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the YUV color space mode. */ +gceSTATUS +gco2D_SetYUVColorMode( + IN gco2D Engine, + IN gce2D_YUV_COLOR_MODE Mode + ); + +/* Setup the source global color value in ARGB8 format. */ +gceSTATUS gco2D_SetSourceGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the target global color value in ARGB8 format. */ +gceSTATUS gco2D_SetTargetGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the source and target pixel multiply modes. */ +gceSTATUS +gco2D_SetPixelMultiplyModeAdvanced( + IN gco2D Engine, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha, + IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha + ); + +/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */ +gceSTATUS +gco2D_SetAutoFlushCycles( + IN gco2D Engine, + IN gctUINT32 Cycles + ); + +/* Read the profile registers available in the 2D engine and sets them in the profile. + The function will also reset the pixelsRendered counter every time. +*/ +gceSTATUS +gco2D_ProfileEngine( + IN gco2D Engine, + OPTIONAL gcs2D_PROFILE_PTR Profile + ); + +/* Enable or disable 2D dithering. */ +gceSTATUS +gco2D_EnableDither( + IN gco2D Engine, + IN gctBOOL Enable + ); + +gceSTATUS +gco2D_SetGenericSource( + IN gco2D Engine, + IN gctUINT32_PTR Addresses, + IN gctUINT32 AddressNum, + IN gctUINT32_PTR Strides, + IN gctUINT32 StrideNum, + IN gceTILING Tiling, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight +); + +gceSTATUS +gco2D_SetGenericTarget( + IN gco2D Engine, + IN gctUINT32_PTR Addresses, + IN gctUINT32 AddressNum, + IN gctUINT32_PTR Strides, + IN gctUINT32 StrideNum, + IN gceTILING Tiling, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight +); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_raster_h_ */ + diff --git a/kernel_drivers/v2/hal/inc/gc_hal_types.h b/kernel_drivers/v2/hal/inc/gc_hal_types.h new file mode 100644 index 0000000..b66595e --- /dev/null +++ b/kernel_drivers/v2/hal/inc/gc_hal_types.h @@ -0,0 +1,545 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_types_h_ +#define __gc_hal_types_h_ + +#include "gc_hal_options.h" + +#ifdef _WIN32 +#pragma warning(disable:4127) /* Conditional expression is constant (do { } + ** while(0)). */ +#pragma warning(disable:4100) /* Unreferenced formal parameter. */ +#pragma warning(disable:4204) /* Non-constant aggregate initializer (C99). */ +#pragma warning(disable:4131) /* Uses old-style declarator (for Bison and + ** Flex generated files). */ +#pragma warning(disable:4206) /* Translation unit is empty. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +** Platform macros. +*/ + +#if defined(__GNUC__) +# define gcdHAS_ELLIPSES 1 /* GCC always has it. */ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define gcdHAS_ELLIPSES 1 /* C99 has it. */ +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) +# define gcdHAS_ELLIPSES 1 /* MSVC 2007+ has it. */ +#elif defined(UNDER_CE) +# define gcdHAS_ELLIPSES 0 /* Windows CE doesn't have it. */ +#else +# error "gcdHAS_ELLIPSES: Platform could not be determined" +#endif + +/******************************************************************************\ +************************************ Keyword *********************************** +\******************************************************************************/ + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) +# define gcmINLINE inline /* C99 keyword. */ +#elif defined(__GNUC__) +# define gcmINLINE __inline__ /* GNU keyword. */ +#elif defined(_MSC_VER) || defined(UNDER_CE) +# define gcmINLINE __inline /* Internal keyword. */ +#else +# error "gcmINLINE: Platform could not be determined" +#endif + +#ifndef gcdDEBUG +# if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG) +# define gcdDEBUG 1 +# else +# define gcdDEBUG 0 +# endif +#endif + +#ifdef _USRDLL +# ifdef _MSC_VER +# ifdef HAL_EXPORTS +# define HALAPI __declspec(dllexport) +# else +# define HALAPI __declspec(dllimport) +# endif +# define HALDECL __cdecl +# else +# ifdef HAL_EXPORTS +# define HALAPI +# else +# define HALAPI extern +# endif +# endif +#else +# define HALAPI +# define HALDECL +#endif + +/******************************************************************************\ +********************************** Common Types ******************************** +\******************************************************************************/ + +#define gcvFALSE 0 +#define gcvTRUE 1 + +#define gcvINFINITE ((gctUINT32) ~0U) + +typedef int gctBOOL; +typedef gctBOOL * gctBOOL_PTR; + +typedef int gctINT; +typedef signed char gctINT8; +typedef signed short gctINT16; +typedef signed int gctINT32; +typedef signed long long gctINT64; + +typedef gctINT * gctINT_PTR; +typedef gctINT8 * gctINT8_PTR; +typedef gctINT16 * gctINT16_PTR; +typedef gctINT32 * gctINT32_PTR; +typedef gctINT64 * gctINT64_PTR; + +typedef unsigned int gctUINT; +typedef unsigned char gctUINT8; +typedef unsigned short gctUINT16; +typedef unsigned int gctUINT32; +typedef unsigned long long gctUINT64; + +typedef gctUINT * gctUINT_PTR; +typedef gctUINT8 * gctUINT8_PTR; +typedef gctUINT16 * gctUINT16_PTR; +typedef gctUINT32 * gctUINT32_PTR; +typedef gctUINT64 * gctUINT64_PTR; + +typedef unsigned long gctSIZE_T; +typedef gctSIZE_T * gctSIZE_T_PTR; + +#ifdef __cplusplus +# define gcvNULL 0 +#else +# define gcvNULL ((void *) 0) +#endif + +typedef float gctFLOAT; +typedef signed int gctFIXED_POINT; +typedef float * gctFLOAT_PTR; + +typedef void * gctPHYS_ADDR; +typedef void * gctHANDLE; +typedef void * gctFILE; +typedef void * gctSIGNAL; +typedef void * gctWINDOW; +typedef void * gctIMAGE; + +typedef void * gctPOINTER; +typedef const void * gctCONST_POINTER; + +typedef char gctCHAR; +typedef char * gctSTRING; +typedef const char * gctCONST_STRING; + +typedef struct _gcsCOUNT_STRING +{ + gctSIZE_T Length; + gctCONST_STRING String; +} +gcsCOUNT_STRING; + +/* Fixed point constants. */ +#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) +#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) +#define gcvONE_X ((gctFIXED_POINT) 0x00010000) +#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) +#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) + +/******************************************************************************\ +******************************* Fixed Point Math ******************************* +\******************************************************************************/ + +#define gcmXMultiply(x1, x2) \ + (gctFIXED_POINT) (((gctINT64) (x1) * (x2)) >> 16) + +#define gcmXDivide(x1, x2) \ + (gctFIXED_POINT) ((((gctINT64) (x1)) << 16) / (x2)) + +#define gcmXMultiplyDivide(x1, x2, x3) \ + (gctFIXED_POINT) ((gctINT64) (x1) * (x2) / (x3)) + +/* 2D Engine profile. */ +struct gcs2D_PROFILE +{ + /* Cycle count. + 32bit counter incremented every 2D clock cycle. + Wraps back to 0 when the counter overflows. + */ + gctUINT32 cycleCount; + + /* Pixels rendered by the 2D engine. + Resets to 0 every time it is read. */ + gctUINT32 pixelsRendered; +}; + + +/* Macro to combine four characters into a Charcater Code. */ +#define gcmCC(c1, c2, c3, c4) \ +( \ + (char) (c1) \ + | \ + ((char) (c2) << 8) \ + | \ + ((char) (c3) << 16) \ + | \ + ((char) (c4) << 24) \ +) + +#define gcmPRINTABLE(c) ((((c) >= ' ') && ((c) <= '}')) ? (c) : ' ') + +#define gcmCC_PRINT(cc) \ + gcmPRINTABLE((char) ( (cc) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 8) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 24) & 0xFF)) + +/******************************************************************************\ +****************************** Function Parameters ***************************** +\******************************************************************************/ + +#define IN +#define OUT +#define OPTIONAL + +/******************************************************************************\ +********************************* Status Codes ********************************* +\******************************************************************************/ + +typedef enum _gceSTATUS +{ + gcvSTATUS_OK = 0, + gcvSTATUS_FALSE = 0, + gcvSTATUS_TRUE = 1, + gcvSTATUS_NO_MORE_DATA = 2, + gcvSTATUS_CACHED = 3, + gcvSTATUS_MIPMAP_TOO_LARGE = 4, + gcvSTATUS_NAME_NOT_FOUND = 5, + gcvSTATUS_NOT_OUR_INTERRUPT = 6, + gcvSTATUS_MISMATCH = 7, + gcvSTATUS_MIPMAP_TOO_SMALL = 8, + gcvSTATUS_LARGER = 9, + gcvSTATUS_SMALLER = 10, + gcvSTATUS_CHIP_NOT_READY = 11, + gcvSTATUS_NEED_CONVERSION = 12, + gcvSTATUS_SKIP = 13, + gcvSTATUS_DATA_TOO_LARGE = 14, + gcvSTATUS_INVALID_CONFIG = 15, + gcvSTATUS_CHANGED = 16, + gcvSTATUS_NOT_SUPPORT_DITHER = 17, + + gcvSTATUS_INVALID_ARGUMENT = -1, + gcvSTATUS_INVALID_OBJECT = -2, + gcvSTATUS_OUT_OF_MEMORY = -3, + gcvSTATUS_MEMORY_LOCKED = -4, + gcvSTATUS_MEMORY_UNLOCKED = -5, + gcvSTATUS_HEAP_CORRUPTED = -6, + gcvSTATUS_GENERIC_IO = -7, + gcvSTATUS_INVALID_ADDRESS = -8, + gcvSTATUS_CONTEXT_LOSSED = -9, + gcvSTATUS_TOO_COMPLEX = -10, + gcvSTATUS_BUFFER_TOO_SMALL = -11, + gcvSTATUS_INTERFACE_ERROR = -12, + gcvSTATUS_NOT_SUPPORTED = -13, + gcvSTATUS_MORE_DATA = -14, + gcvSTATUS_TIMEOUT = -15, + gcvSTATUS_OUT_OF_RESOURCES = -16, + gcvSTATUS_INVALID_DATA = -17, + gcvSTATUS_INVALID_MIPMAP = -18, + gcvSTATUS_NOT_FOUND = -19, + gcvSTATUS_NOT_ALIGNED = -20, + gcvSTATUS_INVALID_REQUEST = -21, + gcvSTATUS_GPU_NOT_RESPONDING = -22, + + /* Linker errors. */ + gcvSTATUS_GLOBAL_TYPE_MISMATCH = -1000, + gcvSTATUS_TOO_MANY_ATTRIBUTES = -1001, + gcvSTATUS_TOO_MANY_UNIFORMS = -1002, + gcvSTATUS_TOO_MANY_VARYINGS = -1003, + gcvSTATUS_UNDECLARED_VARYING = -1004, + gcvSTATUS_VARYING_TYPE_MISMATCH = -1005, + gcvSTATUS_MISSING_MAIN = -1006, + gcvSTATUS_NAME_MISMATCH = -1007, + gcvSTATUS_INVALID_INDEX = -1008, +} +gceSTATUS; + +/******************************************************************************\ +********************************* Status Macros ******************************** +\******************************************************************************/ + +#define gcmIS_ERROR(status) (status < 0) +#define gcmNO_ERROR(status) (status >= 0) +#define gcmIS_SUCCESS(status) (status == gcvSTATUS_OK) + +/******************************************************************************\ +********************************* Field Macros ********************************* +\******************************************************************************/ + +#define __gcmSTART(reg_field) \ + (0 ? reg_field) + +#define __gcmEND(reg_field) \ + (1 ? reg_field) + +#define __gcmGETSIZE(reg_field) \ + (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1) + +#define __gcmALIGN(data, reg_field) \ + (((gctUINT32) (data)) << __gcmSTART(reg_field)) + +#define __gcmMASK(reg_field) \ + ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \ + ? ~0 \ + : (~(~0 << __gcmGETSIZE(reg_field))))) + +/******************************************************************************* +** +** gcmFIELDMASK +** +** Get aligned field mask. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +*/ +#define gcmFIELDMASK(reg, field) \ +( \ + __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmGETFIELD +** +** Extract the value of a field from specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +*/ +#define gcmGETFIELD(data, reg, field) \ +( \ + ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \ + & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** +** gcmSETFIELD +** +** Set the value of a field within specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETFIELD(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN((gctUINT32) (value) \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmSETFIELDVALUE +** +** Set the value of a field within specified data with a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmSETFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN(reg##_##field##_##value \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmSETMASKEDFIELD +** +** Set the value of a masked field with specified data. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETMASKEDFIELD(reg, field, value) \ +( \ + ((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? reg_field) - (0 ? reg_field) + 1) == 32) ? ~0 : (~(~0 << ((1 ? reg_field) - (0 ? reg_field) + 1))))))) << (0 ? reg_field))) | (((gctUINT32) ((gctUINT32) (value) & ((gctUINT32) ((((1 ? reg_field) - (0 ? reg_field) + 1) == 32) ? ~0 : (~(~0 << ((1 ? reg_field) - (0 ? reg_field) + 1))))))) << (0 ? reg_field)))&\ + ((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? reg_MASK_##field) - (0 ? reg_MASK_##field) + 1) == 32) ? ~0 : (~(~0 << ((1 ? reg_MASK_##field) - (0 ? reg_MASK_##field) + 1))))))) << (0 ? reg_MASK_##field))) | (((gctUINT32) (reg_MASK_##field_ENABLED&((gctUINT32)((((1?reg_MASK_##field)-(0?reg_MASK_##field)+1)==32)?~0:(~(~0<<((1?reg_MASK_##field)-(0?reg_MASK_##field)+1)))))))<<(0?reg_MASK_##field)))\ +) + +/******************************************************************************* +** +** gcmVERIFYFIELDVALUE +** +** Verify if the value of a field within specified data equals a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmVERIFYFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \ + __gcmMASK(reg##_##field)) \ + == \ + (reg##_##field##_##value & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** Bit field macros. +*/ + +#define __gcmSTARTBIT(Field) \ + ( 1 ? Field ) + +#define __gcmBITSIZE(Field) \ + ( 0 ? Field ) + +#define __gcmBITMASK(Field) \ +( \ + (1 << __gcmBITSIZE(Field)) - 1 \ +) + +#define gcmGETBITS(Value, Type, Field) \ +( \ + ( ((Type) (Value)) >> __gcmSTARTBIT(Field) ) \ + & \ + __gcmBITMASK(Field) \ +) + +#define gcmSETBITS(Value, Type, Field, NewValue) \ +( \ + ( ((Type) (Value)) \ + & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \ + ) \ + | \ + ( ( ((Type) (NewValue)) \ + & __gcmBITMASK(Field) \ + ) << __gcmSTARTBIT(Field) \ + ) \ +) + +/******************************************************************************\ +******************************** Min/Max Macros ******************************** +\******************************************************************************/ + +#define gcmMIN(x, y) (((x) <= (y)) ? (x) : (y)) +#define gcmMAX(x, y) (((x) >= (y)) ? (x) : (y)) +#define gcmCLAMP(x, min, max) (((x) < (min)) ? (min) : \ + ((x) > (max)) ? (max) : (x)) +#define gcmABS(x) (((x) < 0) ? -(x) : (x)) +#define gcmNEG(x) (((x) < 0) ? (x) : -(x)) + +/******************************************************************************* +** +** gcmPTR2INT +** +** Convert a pointer to an integer value. +** +** ARGUMENTS: +** +** p Pointer value. +*/ +#if defined(_WIN32) || (defined(__LP64__) && __LP64__) +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (gctUINT64) (p) \ + ) +#else +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (p) \ + ) +#endif + +/******************************************************************************* +** +** gcmINT2PTR +** +** Convert an integer value into a pointer. +** +** ARGUMENTS: +** +** v Integer value. +*/ +#define gcmINT2PTR(i) \ +( \ + (gctPOINTER) (i) \ +) + +/******************************************************************************* +** +** gcmOFFSETOF +** +** Compute the byte offset of a field inside a structure. +** +** ARGUMENTS: +** +** s Structure name. +** field Field name. +*/ +#define gcmOFFSETOF(s, field) \ +( \ + gcmPTR2INT(& (((struct s *) 0)->field)) \ +) + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_types_h_ */ + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel.c new file mode 100644 index 0000000..71a0798 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel.c @@ -0,0 +1,1255 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_Construct +** +** Construct a new gckKERNEL object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN gctPOINTER Context +** Pointer to a driver defined context. +** +** OUTPUT: +** +** gckKERNEL * Kernel +** Pointer to a variable that will hold the pointer to the gckKERNEL +** object. +*/ + +#ifdef ANDROID +#if gcdNEW_PROFILER_FILE +#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.vpd" +#else +#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.xml" +#endif +#else +#if gcdNEW_PROFILER_FILE +#define DEFAULT_PROFILE_FILE_NAME "vprofiler.vpd" /* "vpd" means "vprofile data" */ +#else +#define DEFAULT_PROFILE_FILE_NAME "vprofiler.xml" +#endif +#endif + +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + OUT gckKERNEL * Kernel + ) +{ + gckKERNEL kernel = gcvNULL; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); + + /* Allocate the gckKERNEL object. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(struct _gckKERNEL), + (gctPOINTER *) &kernel)); + + /* Zero the object pointers. */ + kernel->hardware = gcvNULL; + kernel->command = gcvNULL; + kernel->event = gcvNULL; + kernel->mmu = gcvNULL; + + /* Initialize the gckKERNEL object. */ + kernel->object.type = gcvOBJ_KERNEL; + kernel->os = Os; + + /* Save context. */ + kernel->context = Context; + + /* Construct atom holding number of clients. */ + kernel->atomClients = gcvNULL; + gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients)); + +#if gcdSECURE_USER + kernel->cacheSlots = 0; + kernel->cacheTimeStamp = 0; +#endif + + /* Construct the gckHARDWARE object. */ + gcmkONERROR( + gckHARDWARE_Construct(Os, &kernel->hardware)); + + /* Set pointer to gckKERNEL object in gckHARDWARE object. */ + kernel->hardware->kernel = kernel; + + /* Initialize the hardware. */ + gcmkONERROR( + gckHARDWARE_InitializeHardware(kernel->hardware)); + + /* Construct the gckCOMMAND object. */ + gcmkONERROR( + gckCOMMAND_Construct(kernel, &kernel->command)); + + /* Construct the gckEVENT object. */ + gcmkONERROR( + gckEVENT_Construct(kernel, &kernel->event)); + + /* Construct the gckMMU object. */ + gcmkONERROR( + gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu)); + +#if VIVANTE_PROFILER + /* Initialize profile setting */ +#if defined ANDROID + kernel->profileEnable = gcvFALSE; +#else + kernel->profileEnable = gcvTRUE; +#endif + + gcmkVERIFY_OK( + gckOS_MemCopy(kernel->profileFileName, + DEFAULT_PROFILE_FILE_NAME, + gcmSIZEOF(DEFAULT_PROFILE_FILE_NAME) + 1)); +#endif + + /* Return pointer to the gckKERNEL object. */ + *Kernel = kernel; + + /* Success. */ + gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); + return gcvSTATUS_OK; + +OnError: + if (kernel != gcvNULL) + { + if (kernel->event != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_Destroy(kernel->event)); + } + + if (kernel->command != gcvNULL) + { + gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command)); + } + + if (kernel->hardware != gcvNULL) + { + gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware)); + } + + if (kernel->atomClients != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients)); + } + + gcmkVERIFY_OK(gckOS_Free(Os, kernel)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Destroy +** +** Destroy an gckKERNEL object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ) +{ + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Destroy the gckMMU object. */ + gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu)); + + /* Destroy the gckEVENT object. */ + gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->event)); + + /* Destroy the gckCOMMNAND object. */ + gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command)); + + /* Destroy the gckHARDWARE object. */ + gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware)); + + /* Detsroy the client atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients)); + + /* Mark the gckKERNEL object as unknown. */ + Kernel->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckKERNEL object. */ + gcmkVERIFY_OK(gckOS_Free(Kernel->os, Kernel)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** _AllocateMemory +** +** Private function to walk all required memory pools to allocate the requested +** amount of video memory. +** +** 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. +*/ +static gceSTATUS +_AllocateMemory( + IN gckKERNEL Kernel, + IN OUT gcePOOL * Pool, + IN gctSIZE_T Bytes, + IN gctSIZE_T Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gcePOOL pool; + gceSTATUS status; + gckVIDMEM videoMemory; + + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + + /* Get initial pool. */ + switch (pool = *Pool) + { + case gcvPOOL_DEFAULT: + case gcvPOOL_LOCAL: + pool = gcvPOOL_LOCAL_INTERNAL; + break; + + case gcvPOOL_UNIFIED: + pool = gcvPOOL_SYSTEM; + break; + + default: + break; + } + + do + { + /* Verify the number of bytes to allocate. */ + if (Bytes == 0) + { + gcmkERR_BREAK(gcvSTATUS_INVALID_ARGUMENT); + } + + if (pool == gcvPOOL_VIRTUAL) + { + /* Create a gcuVIDMEM_NODE for virtual memory. */ +#ifdef __QNXNTO__ + gcmkERR_BREAK( + gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Handle, Node)); +#else + gcmkERR_BREAK( + gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node)); +#endif + + /* Success. */ + break; + } + else if (pool == gcvPOOL_CONTIGUOUS) + { + /* Create a gcuVIDMEM_NODE for contiguous memory. */ +#ifdef __QNXNTO__ + status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Handle, Node); +#else + status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, Node); +#endif + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + break; + } + } + else + { + /* Get pointer to gckVIDMEM object for pool. */ + status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); + + if (gcmIS_SUCCESS(status)) + { + /* Allocate memory. */ + status = gckVIDMEM_AllocateLinear(videoMemory, + Bytes, + Alignment, + Type, +#ifdef __QNXNTO__ + Handle, +#endif + Node); + + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + (*Node)->VidMem.pool = pool; + break; + } + } + } + + if (pool == gcvPOOL_LOCAL_INTERNAL) + { + /* Advance to external memory. */ + pool = gcvPOOL_LOCAL_EXTERNAL; + } + else + if (pool == gcvPOOL_LOCAL_EXTERNAL) + { + /* Advance to contiguous system memory. */ + pool = gcvPOOL_SYSTEM; + } + else + if (pool == gcvPOOL_SYSTEM) + { + /* Advance to contiguous memory. */ + pool = gcvPOOL_CONTIGUOUS; + } + else + if ((pool == gcvPOOL_CONTIGUOUS) + && (Type != gcvSURF_TILE_STATUS) + ) + { + /* Advance to virtual memory. */ + pool = gcvPOOL_VIRTUAL; + } + else + { + /* Out of pools. */ + break; + } + } + /* Loop only for multiple selection pools. */ + while ((*Pool == gcvPOOL_DEFAULT) + || (*Pool == gcvPOOL_LOCAL) + || (*Pool == gcvPOOL_UNIFIED) + ); + + if (gcmIS_SUCCESS(status)) + { + /* Return pool used for allocation. */ + *Pool = pool; + } + + /* Return status. */ + 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, + &Interface->u.QueryChipIdentity.chipMinorFeatures2)); + + /* 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: + /* 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.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; + +#if gcdGPU_TIMEOUT + case gcvHAL_BROADCAST_GPU_STUCK: + /* Broadcast GPU stuck */ + status = gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_GPU_STUCK); + break; +#endif + + 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; +} + +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(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_FIRST_PROCESS)); + } + } + + else + { + /* Decrement the number of clients attached. */ + gcmkONERROR( + gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); + + if (old == 1) + { + /* Last client detached, switch to SUSPEND power state. */ + gcmkONERROR(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_LAST_PROCESS)); + + /* Flush the debug cache. */ + gcmkPRINT("$$FLUSH$$"); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gctHANDLE Process, + IN OUT gctPOINTER * Data + ) +{ + gctUINT i, oldest; + gceSTATUS status; + gctUINT32 baseAddress; + + gcmkHEADER_ARG("Kernel=0x%x Process=0x%x *Data=0x%x", + Kernel, Process, gcmOPT_POINTER(Data)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + /* Get base address. */ + gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress)); + + /* Walk all used cache slots. */ + for (i = oldest = 0; i < Kernel->cacheSlots; ++i) + { + if ((Kernel->cache[i].logical == *Data) + && (Kernel->cache[i].process == Process) + ) + { + /* Bail out. */ + break; + } + + if (i == 0) + { + /* First slot. */ + oldest = i; + } + + /* Test if this cache slot is older. */ + else if (Kernel->cache[i].stamp < Kernel->cache[oldest].stamp) + { + oldest = i; + } + } + + /* See if we had a match. */ + if (i == Kernel->cacheSlots) + { + /* See if there is room in the cache. */ + if (i < gcmCOUNTOF(Kernel->cache)) + { + /* Just append to the cache. */ + i = Kernel->cacheSlots++; + } + + else + { + /* Evict the oldest cache line. */ + i = oldest; + } + + /* Initialize the cache line. */ + Kernel->cache[i].logical = *Data; + Kernel->cache[i].process = Process; + + /* Map the logical address to a DMA address. */ + gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, + *Data, + &Kernel->cache[i].dma)); + + if (baseAddress != 0) + { + gctBOOL needBase; + + /* Does this state load need a base address? */ + gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware, + ((gctUINT32_PTR) Data)[-1], + &needBase)); + + if (needBase) + { + /* Add the base address. */ + Kernel->cache[i].dma += baseAddress; + } + } + } + + /* Increment time stamp of the cache slot. */ + Kernel->cache[i].stamp = Kernel->cacheTimeStamp++; + + /* Return DMA address. */ + *Data = gcmINT2PTR(Kernel->cache[i].dma); + + /* Success. */ + gcmkFOOTER_ARG("*Data=0x%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ) +{ + gceSTATUS status; + gckEVENT event; + gckHARDWARE hardware; +#if gcdSECURE_USER + gctUINT32 processID; +#endif + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Validate the arguemnts. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Grab gckEVENT object. */ + event = Kernel->event; + gcmkVERIFY_OBJECT(event, gcvOBJ_EVENT); + + /* Grab gckHARDWARE object. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Handle all outstanding events now. */ + event->pending = ~0U; + gcmkONERROR(gckEVENT_Notify(event, 1)); + + /* Again in case more events got submitted. */ + event->pending = ~0U; + gcmkONERROR(gckEVENT_Notify(event, 2)); + +#if gcdSECURE_USER + /* Flush the secure mapping cache. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + gcmkONERROR(gckKERNEL_MapLogicalToPhysical(Kernel, processID, gcvNULL)); +#endif + + /* Try issuing a soft reset for the GPU. */ + status = gckHARDWARE_Reset(hardware); + if (status == gcvSTATUS_NOT_SUPPORTED) + { + /* Switch to OFF power. The next submit should return the GPU to ON + ** state. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(hardware, + gcvPOWER_OFF_RECOVERY)); + } + else + { + /* Bail out on reset error. */ + gcmkONERROR(status); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel.h b/kernel_drivers/v2/hal/kernel/gc_hal_kernel.h new file mode 100644 index 0000000..2545cd1 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel.h @@ -0,0 +1,406 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_h_ +#define __gc_hal_kernel_h_ + +#include "gc_hal.h" +#include "gc_hal_kernel_hardware.h" +#include "gc_hal_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +#if gcdSECURE_USER +typedef struct _gckLOGICAL_CACHE +{ + gctHANDLE process; + gctPOINTER logical; + gctUINT32 dma; + gctUINT64 stamp; +} +gckLOGICAL_CACHE; +#endif + +/* gckKERNEL object. */ +struct _gckKERNEL +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* Pointer to gckCOMMAND object. */ + gckCOMMAND command; + + /* Pointer to gckEVENT object. */ + gckEVENT event; + + /* Pointer to context. */ + gctPOINTER context; + + /* Pointer to gckMMU object. */ + gckMMU mmu; + + /* Arom holding number of clients. */ + gctPOINTER atomClients; + +#if VIVANTE_PROFILER + /* Enable profiling */ + gctBOOL profileEnable; + + /* The profile file name */ + gctCHAR profileFileName[gcdMAX_PROFILE_FILE_NAME]; +#endif + +#if gcdSECURE_USER + gckLOGICAL_CACHE cache[gcdSECURE_CACHE_SLOTS]; + gctUINT cacheSlots; + gctUINT64 cacheTimeStamp; +#endif +}; + +#define gcdCOMMAND_QUEUES 2 + +/* gckCOMMAND object. */ +struct _gckCOMMAND +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to required object. */ + gckKERNEL kernel; + gckOS os; + + /* Number of bytes per page. */ + gctSIZE_T pageSize; + + /* Current pipe select. */ + gctUINT32 pipeSelect; + + /* Command queue running flag. */ + gctBOOL running; + + /* Idle flag and commit stamp. */ + gctBOOL idle; + gctUINT64 commitStamp; + + /* Command queue mutex. */ + gctPOINTER mutexQueue; + + /* Context switching mutex. */ + gctPOINTER mutexContext; + + /* Command queue power semaphore. */ + gctPOINTER powerSemaphore; + + /* Current command queue. */ + struct _gcskCOMMAND_QUEUE + { + gctSIGNAL signal; + gctPHYS_ADDR physical; + gctPOINTER logical; + } + queues[gcdCOMMAND_QUEUES]; + + gctPHYS_ADDR physical; + gctPOINTER logical; + gctINT index; + gctUINT32 offset; + + /* The command queue is new. */ + gctBOOL newQueue; + gctBOOL submit; + + /* Context counter used for unique ID. */ + gctUINT64 contextCounter; + + /* Current context ID. */ + gctUINT64 currentContext; + + /* Pointer to last WAIT command. */ + gctPOINTER wait; + gctSIZE_T waitSize; + + /* Command buffer alignment. */ + gctSIZE_T alignment; + gctSIZE_T reservedHead; + gctSIZE_T reservedTail; + + /* Commit counter. */ + gctPOINTER atomCommit; +}; + +typedef struct _gcsEVENT * gcsEVENT_PTR; + +/* Structure holding one event to be processed. */ +typedef struct _gcsEVENT +{ + /* Pointer to next event in queue. */ + gcsEVENT_PTR next; + + /* Event information. */ + gcsHAL_INTERFACE event; + +#ifdef __QNXNTO__ + /* Kernel. */ + gckKERNEL kernel; +#endif +} +gcsEVENT; + +/* Structure holding a list of events to be processed by an interrupt. */ +typedef struct _gcsEVENT_QUEUE +{ + /* Time stamp. */ + gctUINT64 stamp; + + /* Source of the event. */ + gceKERNEL_WHERE source; + + /* Pointer to head of event queue. */ + gcsEVENT_PTR head; + + /* Pointer to tail of event queue. */ + gcsEVENT_PTR tail; + + /* Process ID owning the event queue. */ + gctUINT32 processID; +} +gcsEVENT_QUEUE; + +/* gckEVENT object. */ +struct _gckEVENT +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to required objects. */ + gckOS os; + gckKERNEL kernel; + + /* Time stamp. */ + gctUINT64 stamp; + gctUINT64 lastCommitStamp; + + /* Queue mutex. */ + gctPOINTER mutexQueue; + + /* Array of event queues. */ + gcsEVENT_QUEUE queues[31]; + gctUINT8 lastID; + + /* Pending events. */ + volatile gctUINT pending; + + /* List of free event structures and its mutex. */ + gcsEVENT_PTR freeList; + gctSIZE_T freeCount; + gctPOINTER freeMutex; + + /* Events queued to be added to an event queue and its mutex. */ + gcsEVENT_QUEUE list; + gctPOINTER listMutex; +}; + +/* gcuVIDMEM_NODE structure. */ +typedef union _gcuVIDMEM_NODE +{ + /* Allocated from gckVIDMEM. */ + struct _gcsVIDMEM_NODE_VIDMEM + { + /* Owner of this node. */ + gckVIDMEM memory; + + /* Dual-linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + gcuVIDMEM_NODE_PTR prev; + + /* Dual linked list of free nodes. */ + gcuVIDMEM_NODE_PTR nextFree; + gcuVIDMEM_NODE_PTR prevFree; + + /* Information for this node. */ + gctUINT32 offset; + gctSIZE_T bytes; + gctUINT32 alignment; + +#ifdef __QNXNTO__ + /* Client/server vaddr (mapped using mmap_join). */ + gctPOINTER logical; + + /* Unique handle of the caller process channel. */ + gctHANDLE handle; +#endif + + /* Locked counter. */ + gctINT32 locked; + + /* Memory pool. */ + gcePOOL pool; + gctUINT32 physical; + } + VidMem; + + /* Allocated from gckOS. */ + struct _gcsVIDMEM_NODE_VIRTUAL + { + /* Pointer to gckKERNEL object. */ + gckKERNEL kernel; + + /* Information for this node. */ + gctBOOL contiguous; + gctPHYS_ADDR physical; + gctSIZE_T bytes; + gctPOINTER logical; + + /* Page table information. */ + gctSIZE_T pageCount; + gctPOINTER pageTable; + gctUINT32 address; + + /* Mutex. */ + gctPOINTER mutex; + + /* Locked counter. */ + gctINT32 locked; + +#ifdef __QNXNTO__ + /* Single linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + + /* PID of the caller process channel. */ + gctUINT32 userPID; + + /* Unique handle of the caller process channel. */ + gctHANDLE handle; + + /* Unlock pending flag. */ + gctBOOL unlockPending; + + /* Free pending flag. */ + gctBOOL freePending; +#else + /* Pending flag. */ + gctBOOL pending; +#endif + } + Virtual; +} +gcuVIDMEM_NODE; + +/* gckVIDMEM object. */ +struct _gckVIDMEM +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Information for this video memory heap. */ + gctUINT32 baseAddress; + gctSIZE_T bytes; + gctSIZE_T freeBytes; + + /* Mapping for each type of surface. */ + gctINT mapping[gcvSURF_NUM_TYPES]; + + /* Sentinel nodes for up to 8 banks. */ + gcuVIDMEM_NODE sentinel[8]; + + /* Allocation threshold. */ + gctSIZE_T threshold; + + /* The heap mutex. */ + gctPOINTER mutex; +}; + +/* gckMMU object. */ +struct _gckMMU +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* The page table mutex. */ + gctPOINTER pageTableMutex; + + /* Page table information. */ + gctSIZE_T pageTableSize; + gctPHYS_ADDR pageTablePhysical; + gctUINT32_PTR pageTableLogical; + gctUINT32 pageTableEntries; + + /* Free entries. */ + gctUINT32 heapList; + gctBOOL freeNodes; + +#ifdef __QNXNTO__ + /* Single linked list of all allocated nodes. */ + gctPOINTER nodeMutex; + gcuVIDMEM_NODE_PTR nodeList; +#endif +}; + +gceSTATUS +gckKERNEL_AttachProcess( + IN gckKERNEL Kernel, + IN gctBOOL Attach + ); + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gctHANDLE Process, + IN OUT gctPOINTER * Data + ); +#endif + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_h_ */ + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_command.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_command.c new file mode 100644 index 0000000..7ef56ef --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_command.c @@ -0,0 +1,1936 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_user_context.h" + +#if defined(__QNXNTO__) +#include <sys/slog.h> +#endif + +#define _GC_OBJ_ZONE gcvZONE_COMMAND + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +#if gcdDUMP_COMMAND +static void +_DumpCommand( + IN gckCOMMAND Command, + IN gctPOINTER Pointer, + IN gctSIZE_T Bytes + ) +{ + gctUINT32_PTR data = (gctUINT32_PTR) Pointer; + gctUINT32 address; + + 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"); +} +#endif + +gceSTATUS +_WaitSignalFromGPU( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctSIGNAL Signal + ) +{ + gceSTATUS status; + +#if gcdGPU_TIMEOUT + gctUINT timer = 0; + + do + { + /* Wait for the signal. */ + status = gckOS_WaitSignal(Os, Signal, 250); + + if (status == gcvSTATUS_TIMEOUT) + { +#if gcdDEBUG + gctUINT32 idle; + + /* Read idle register. */ + gcmkVERIFY_OK( + gckHARDWARE_GetIdle(Hardware, + gcvFALSE, + &idle)); + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): idle=%08x", + __FUNCTION__, __LINE__, idle); +#endif + + /* Advance timer. */ + timer += 250; + } + else + { + gcmkONERROR(status); + } + } + while (gcmIS_ERROR(status) && (timer < gcdGPU_TIMEOUT)); + + /* Bail out on timeout. */ + if (gcmIS_ERROR(status)) + { + /* Broadcast the stuck GPU. */ + gcmkONERROR(gckOS_Broadcast(Os, + Hardware, + gcvBROADCAST_GPU_STUCK)); + + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } + +#else + gcmkONERROR(gckOS_WaitSignal(Os, Signal, gcvINFINITE)); +#endif + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** _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 + ) +{ + gceSTATUS status; + gctINT currentIndex, newIndex; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* 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( + _WaitSignalFromGPU(Command->os, + Command->kernel->hardware, + Command->queues[newIndex].signal)); + + if (currentIndex >= 0) + { + /* Mark the command queue as available. */ + gcmkONERROR(gckEVENT_Signal(Command->kernel->event, + Command->queues[currentIndex].signal, + gcvKERNEL_COMMAND)); + } + + /* 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; +} + +/******************************************************************************\ +****************************** gckCOMMAND API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckCOMMAND_Construct +** +** Construct a new gckCOMMAND object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckCOMMAND * Command +** Pointer to a variable that will hold the pointer to the gckCOMMAND +** object. +*/ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ) +{ + gckOS os; + gckCOMMAND command = gcvNULL; + gceSTATUS status; + gctINT i; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Command != gcvNULL); + + /* Extract the gckOS object. */ + os = Kernel->os; + + /* Allocate the gckCOMMAND structure. */ + gcmkONERROR( + gckOS_Allocate(os, + gcmSIZEOF(struct _gckCOMMAND), + (gctPOINTER *) &command)); + + /* Initialize the gckCOMMAND object.*/ + command->object.type = gcvOBJ_COMMAND; + command->kernel = Kernel; + command->os = os; + command->mutexQueue = gcvNULL; + command->mutexContext = gcvNULL; + command->powerSemaphore = gcvNULL; + command->atomCommit = gcvNULL; + + /* No command queues created yet. */ + command->index = 0; + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + command->queues[i].signal = gcvNULL; + command->queues[i].logical = gcvNULL; + } + + /* Get the command buffer requirements. */ + gcmkONERROR( + gckHARDWARE_QueryCommandBuffer(Kernel->hardware, + &command->alignment, + &command->reservedHead, + &command->reservedTail)); + + /* No contexts available yet. */ + command->contextCounter = command->currentContext = 0; + + /* Create the command queue mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &command->mutexQueue)); + + /* Create the context switching mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &command->mutexContext)); + + /* Create the power management semaphore. */ + gcmkONERROR( + gckOS_CreateSemaphore(os, &command->powerSemaphore)); + + /* Create the commit atom. */ + gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit)); + + /* Get the page size from teh OS. */ + gcmkONERROR( + gckOS_GetPageSize(os, &command->pageSize)); + + /* Set hardware to pipe 0. */ + command->pipeSelect = 0; + + /* Pre-allocate the command queues. */ + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkONERROR( + gckOS_AllocateNonPagedMemory(os, + gcvFALSE, + &command->pageSize, + &command->queues[i].physical, + &command->queues[i].logical)); + gcmkONERROR( + gckOS_CreateSignal(os, gcvFALSE, &command->queues[i].signal)); + + gcmkONERROR( + gckOS_Signal(os, command->queues[i].signal, gcvTRUE)); + } + + /* No command queue in use yet. */ + command->index = -1; + command->logical = gcvNULL; + command->newQueue = gcvFALSE; + command->submit = gcvFALSE; + + /* Command is not yet running. */ + command->running = gcvFALSE; + + /* Command queue is idle. */ + command->idle = gcvTRUE; + + /* Commit stamp is zero. */ + command->commitStamp = 0; + + /* Return pointer to the gckCOMMAND object. */ + *Command = command; + + /* Success. */ + gcmkFOOTER_ARG("*Command=0x%x", *Command); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (command != gcvNULL) + { + if (command->atomCommit != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(os, command->atomCommit)); + } + + if (command->powerSemaphore != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySemaphore(os, command->powerSemaphore)); + } + + if (command->mutexContext != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContext)); + } + + if (command->mutexQueue != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexQueue)); + } + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + if (command->queues[i].signal != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DestroySignal(os, command->queues[i].signal)); + } + + if (command->queues[i].logical != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeNonPagedMemory(os, + command->pageSize, + command->queues[i].physical, + command->queues[i].logical)); + } + } + + gcmkVERIFY_OK(gckOS_Free(os, command)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Destroy +** +** Destroy an gckCOMMAND object. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ) +{ + gctINT i; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Stop the command queue. */ + gcmkVERIFY_OK(gckCOMMAND_Stop(Command)); + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkASSERT(Command->queues[i].signal != gcvNULL); + gcmkVERIFY_OK( + gckOS_DestroySignal(Command->os, Command->queues[i].signal)); + + gcmkASSERT(Command->queues[i].logical != gcvNULL); + gcmkVERIFY_OK( + gckOS_FreeNonPagedMemory(Command->os, + Command->pageSize, + Command->queues[i].physical, + Command->queues[i].logical)); + } + + /* Delete the context switching mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext)); + + /* Delete the command queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue)); + + /* Destroy the power management semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore)); + + /* Destroy the commit atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit)); + + /* Mark object as unknown. */ + Command->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckCOMMAND object. */ + gcmkVERIFY_OK(gckOS_Free(Command->os, Command)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckCOMMAND_Start +** +** Start up the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to start. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ) +{ + gckHARDWARE hardware; + gceSTATUS status; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (Command->running) + { + /* Command queue already running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + if (Command->logical == gcvNULL) + { + /* Start at beginning of a new queue. */ + gcmkONERROR(_NewQueue(Command)); + } + + /* Start at beginning of page. */ + Command->offset = 0; + + /* Append WAIT/LINK. */ + bytes = Command->pageSize; + gcmkONERROR( + gckHARDWARE_WaitLink(hardware, + Command->logical, + 0, + &bytes, + &Command->wait, + &Command->waitSize)); + + /* Flush the cache for the wait/link. */ + gcmkONERROR(gckOS_CacheFlush(Command->os, + gcvNULL, + Command->logical, + bytes)); + + /* Adjust offset. */ + Command->offset = bytes; + Command->newQueue = gcvFALSE; + + /* Enable command processor. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckHARDWARE_Execute(hardware, + Command->logical, + Command->physical, + gcvTRUE, + bytes)); +#else + gcmkONERROR( + gckHARDWARE_Execute(hardware, + Command->logical, + bytes)); +#endif + /* Command queue is running. */ + Command->running = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Stop +** +** Stop the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to stop. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command + ) +{ + gckHARDWARE hardware; + gceSTATUS status; + gctUINT32 idle; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (!Command->running) + { + /* Command queue is not running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Replace last WAIT with END. */ + gcmkONERROR( + gckHARDWARE_End(hardware, + Command->wait, + &Command->waitSize)); + + /* Wait for idle. */ + gcmkONERROR( + gckHARDWARE_GetIdle(hardware, gcvTRUE, &idle)); + + /* Command queue is no longer running. */ + Command->running = gcvFALSE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +typedef struct _gcsMAPPED * gcsMAPPED_PTR; +struct _gcsMAPPED +{ + gcsMAPPED_PTR next; + gctPOINTER pointer; + gctPOINTER kernelPointer; + gctSIZE_T bytes; +}; + +static gceSTATUS +_AddMap( + IN gckOS Os, + IN gctPOINTER Source, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Destination, + IN OUT gcsMAPPED_PTR * Stack + ) +{ + gcsMAPPED_PTR map = gcvNULL; + gceSTATUS status; + + /* Don't try to map NULL pointers. */ + if (Source == gcvNULL) + { + *Destination = gcvNULL; + return gcvSTATUS_OK; + } + + /* Allocate the gcsMAPPED structure. */ + gcmkONERROR( + gckOS_Allocate(Os, gcmSIZEOF(*map), (gctPOINTER *) &map)); + + /* Map the user pointer into kernel addressing space. */ + gcmkONERROR( + gckOS_MapUserPointer(Os, Source, Bytes, Destination)); + + /* Save mapping. */ + map->pointer = Source; + map->kernelPointer = *Destination; + map->bytes = Bytes; + + /* Push structure on top of the stack. */ + map->next = *Stack; + *Stack = map; + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + if (gcmIS_ERROR(status) && (map != gcvNULL)) + { + /* Roll back on error. */ + gcmkVERIFY_OK(gckOS_Free(Os, map)); + } + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** 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 = gcvNULL; + 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; + gctBOOL semaAcquired = gcvFALSE; + gctINT32 atomValue; + gctBOOL atomIncremented = gcvFALSE; + gctBOOL powerAcquired = gcvFALSE; + gctUINT32 process, thread; + + 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); + + /* Get current process and thread IDs. */ + gcmkONERROR(gckOS_GetProcessID(&process)); + gcmkONERROR(gckOS_GetThreadID(&thread)); + + /* Try to acquire the power mutex. */ + status = gckOS_AcquireMutex(Command->os, hardware->powerMutex, 0); + + if (status == gcvSTATUS_OK) + { + hardware->powerProcess = process; + hardware->powerThread = thread; + powerAcquired = gcvTRUE; + } + else if (status == gcvSTATUS_TIMEOUT) + { + /* Check if we already own this mutex. */ + if ((hardware->powerProcess != process) + || (hardware->powerThread != thread) + ) + { + /* Acquire the power mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + hardware->powerMutex, gcvINFINITE)); + + hardware->powerProcess = process; + hardware->powerThread = thread; + powerAcquired = gcvTRUE; + } + } + else + { + gcmkONERROR(status); + } + + /* Increment the commit atom. */ + gcmkONERROR(gckOS_AtomIncrement(Command->os, + Command->atomCommit, + &atomValue)); + atomIncremented = gcvTRUE; + + /* Release the power mutex. */ + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, hardware->powerMutex)); + powerAcquired = gcvFALSE; + } + + /* Notify the system the GPU has a commit. */ + gcmkONERROR(gckOS_Broadcast(Command->os, + hardware, + gcvBROADCAST_GPU_COMMIT)); + + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvTRUE; + + /* 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; + + /* 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; + + /* Save initial buffer to flush. */ + flushPointer = initialLink; + flushSize = initialSize; + + /* Save pointer to next link. */ + link = logical + commandBuffer->offset; + + /* No more data. */ + buffer = gcvNULL; + } + +#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 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)); + + /* 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; + + /* 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)); + + /* 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)); + + /* 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; + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvFALSE; + + /* Submit events if asked for. */ + if (Command->submit) + { + /* Submit events. */ + status = gckEVENT_Submit(Command->kernel->event, 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)); + } + + if (semaAcquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + } + + if (atomIncremented) + { + /* Decrement the commit atom. */ + gcmkVERIFY_OK(gckOS_AtomDecrement(Command->os, + Command->atomCommit, + &atomValue)); + } + + /* 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)); + } + + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, hardware->powerMutex)); + } + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Reserve +** +** Reserve space in the command queue. Also acquire the command queue mutex. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gctSIZE_T RequestedBytes +** Number of bytes previously reserved. +** +** OUTPUT: +** +** gctPOINTER * Buffer +** Pointer to a variable that will receive the address of the reserved +** space. +** +** gctSIZE_T * BufferSize +** Pointer to a variable that will receive the number of bytes +** available in the command queue. +*/ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ) +{ + gceSTATUS status; + gctSIZE_T requiredBytes, bytes; + gctBOOL acquired = gcvFALSE; + gctBOOL semaAcquired = gcvTRUE; + gctINT32 atomValue; + gctBOOL atomIncremented = gcvFALSE; + gctBOOL powerAcquired = gcvFALSE; + gckHARDWARE hardware = gcvNULL; + gctUINT32 process, thread; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Extract the gckHARDWARE objects. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Get current process and thread IDs. */ + gcmkONERROR(gckOS_GetProcessID(&process)); + gcmkONERROR(gckOS_GetThreadID(&thread)); + + /* Try to acquire the power mutex. */ + status = gckOS_AcquireMutex(Command->os, hardware->powerMutex, 0); + + if (status == gcvSTATUS_OK) + { + hardware->powerProcess = process; + hardware->powerThread = thread; + powerAcquired = gcvTRUE; + } + else if (status == gcvSTATUS_TIMEOUT) + { + /* Check if we already own this mutex. */ + if ((hardware->powerProcess != process) + || (hardware->powerThread != thread) + ) + { + /* Acquire the power mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + hardware->powerMutex, gcvINFINITE)); + + hardware->powerProcess = process; + hardware->powerThread = thread; + powerAcquired = gcvTRUE; + } + } + else + { + gcmkONERROR(status); + } + + /* Increment the commit atom. */ + gcmkONERROR( + gckOS_AtomIncrement(Command->os, Command->atomCommit, &atomValue)); + atomIncremented = gcvTRUE; + + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, + Command->kernel->hardware->powerMutex)); + powerAcquired = gcvFALSE; + } + + /* Notify the system the GPU has a commit. */ + gcmkONERROR(gckOS_Broadcast(Command->os, + Command->kernel->hardware, + gcvBROADCAST_GPU_COMMIT)); + + /* Grab the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(Command->os, Command->powerSemaphore)); + semaAcquired = gcvTRUE; + + /* Grab the conmmand queue mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Command->os, + Command->mutexQueue, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Compute number of bytes required for WAIT/LINK. */ + gcmkONERROR( + gckHARDWARE_WaitLink(Command->kernel->hardware, + gcvNULL, + Command->offset + gcmALIGN(RequestedBytes, + Command->alignment), + &requiredBytes, + gcvNULL, + gcvNULL)); + + /* Compute total number of bytes required. */ + requiredBytes += gcmALIGN(RequestedBytes, Command->alignment); + + /* Compute number of bytes available in command queue. */ + bytes = Command->pageSize - Command->offset; + + if (bytes < requiredBytes) + { + /* Create a new command queue. */ + gcmkONERROR(_NewQueue(Command)); + + /* Recompute number of bytes available in command queue. */ + bytes = Command->pageSize - Command->offset; + + if (bytes < requiredBytes) + { + /* Rare case, not enough room in command queue. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + } + + /* Return pointer to empty slot command queue. */ + *Buffer = (gctUINT8 *) Command->logical + Command->offset; + + /* Return number of bytes left in command queue. */ + *BufferSize = bytes; + + /* Success. */ + gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release command queue mutex on error. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + } + + if (semaAcquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + } + + if (atomIncremented) + { + /* Decrement the commit atom. */ + gcmkVERIFY_OK( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + } + + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, + Command->kernel->hardware->powerMutex)); + } + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Release +** +** Release a previously reserved command queue. The command FIFO mutex will be +** released. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Release( + IN gckCOMMAND Command + ) +{ + gceSTATUS status; + gctINT32 atomValue; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Release the command queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + + /* Decrement the commit atom. */ + gcmkONERROR( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + + /* Success. */ + gcmkFOOTER_NO(); + +OnError: + /* 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 + ) +{ + gctUINT32 offset; + gctPOINTER address; + gctSIZE_T bytes; + gceSTATUS status; + gctPOINTER wait; + gctSIZE_T waitBytes; + gctINT32 atomValue; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* 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)); + + /* 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 + + /* Release the command queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, Command->powerSemaphore)); + + /* Submit events if asked for. */ + if (Command->submit) + { + /* Submit events. */ + status = gckEVENT_Submit(Command->kernel->event, gcvFALSE); + + if (gcmIS_SUCCESS(status)) + { + /* Success. */ + Command->submit = gcvFALSE; + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_COMMAND, + "gckEVENT_Submit returned %d", + status); + } + } + + /* Decrement the commit atom. */ + gcmkONERROR( + gckOS_AtomDecrement(Command->os, Command->atomCommit, &atomValue)); + + /* 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; +} + +/******************************************************************************* +** +** 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; + gctUINT timer = 0; + + 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)); + + /* Submit the event queue. */ + gcmkONERROR(gckEVENT_Submit(event, gcvTRUE)); + +#if gcdDUMP_COMMAND + gcmkPRINT("@[kernel.stall]"); +#endif + + if (status == gcvSTATUS_CHIP_NOT_READY) + { + /* Error. */ + goto OnError; + } + + do + { + /* Wait for the signal. */ + status = gckOS_WaitSignalUninterruptible(os, signal, 250); + + if (status == gcvSTATUS_TIMEOUT) + { +#if gcdDEBUG + gctUINT32 idle; + + /* Read idle register. */ + gcmkVERIFY_OK( + gckHARDWARE_GetIdle(Command->kernel->hardware, + gcvFALSE, + &idle)); + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): idle=%08x", + __FUNCTION__, __LINE__, idle); + + gcmkVERIFY_OK( + gckOS_MemoryBarrier(os, gcvNULL)); + +#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 +#endif + /* Advance timer. */ + timer += 250; + } + } + while (gcmIS_ERROR(status) +#if gcdGPU_TIMEOUT + && (timer < gcdGPU_TIMEOUT) +#endif + ); + + /* Bail out on timeout. */ + if (gcmIS_ERROR(status)) + { + /* Broadcast the stuck GPU. */ + gcmkONERROR(gckOS_Broadcast(os, + Command->kernel->hardware, + gcvBROADCAST_GPU_STUCK)); + + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } + + /* 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; +} + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_event.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_event.c new file mode 100644 index 0000000..06c1ef1 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_event.c @@ -0,0 +1,1474 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_user_context.h" + +#define _GC_OBJ_ZONE gcvZONE_EVENT + +#define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsEVENT)) +#define gcdEVENT_MIN_THRESHOLD 4 + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +/******************************************************************************* +** +** _GetEvent +** +** Get an empty event ID. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** gctUINT8 * EventID +** Pointer to a variable that receives an empty event ID. +*/ +static gceSTATUS +_GetEvent( + IN gckEVENT Event, + OUT gctUINT8 * EventID, + IN gceKERNEL_WHERE Source + ) +{ + gctINT i, id; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source); + + /* Grab the queue mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->mutexQueue, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Walk through all events. */ + id = Event->lastID; + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[id].head == gcvNULL) + { + *EventID = (gctUINT8) id; + + Event->lastID = (id + 1) % gcmCOUNTOF(Event->queues); + + /* Save time stamp of event. */ + Event->queues[id].stamp = ++(Event->stamp); + Event->queues[id].source = Source; + + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + + /* Success. */ + gcmkFOOTER_ARG("*EventID=%u", *EventID); + return gcvSTATUS_OK; + } + + id = (id + 1) % gcmCOUNTOF(Event->queues); + } + + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + acquired = gcvFALSE; + + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + +OnError: + if (acquired) + { + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_IsEmpty( + IN gckEVENT Event, + OUT gctBOOL_PTR IsEmpty + ) +{ + gceSTATUS status; + gctSIZE_T i; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL); + + /* Assume the event queue is empty. */ + *IsEmpty = gcvTRUE; + + /* Walk the event queue. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + /* Check whether this event is in use. */ + if (Event->queues[i].head != gcvNULL) + { + /* The event is in use, hence the queue is not empty. */ + *IsEmpty = gcvFALSE; + break; + } + } + + /* Try acquiring the mutex. */ + status = gckOS_AcquireMutex(Event->os, Event->mutexQueue, 0); + if (status == gcvSTATUS_TIMEOUT) + { + /* Timeout - queue is no longer empty. */ + *IsEmpty = gcvFALSE; + } + else + { + /* Bail out on error. */ + gcmkONERROR(status); + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + /* Success. */ + gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +******************************* gckEVENT API Code ******************************* +\******************************************************************************/ + +/******************************************************************************* +** +** gckEVENT_Construct +** +** Construct a new gckEVENT object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckEVENT * Event +** Pointer to a variable that receives the gckEVENT object pointer. +*/ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ) +{ + gckOS os; + gceSTATUS status; + gckEVENT event = gcvNULL; + int i; + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Event != gcvNULL); + + /* Extract the pointer to the gckOS object. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate the gckEVENT object. */ + gcmkONERROR( + gckOS_Allocate(os, + gcmSIZEOF(struct _gckEVENT), + (gctPOINTER *) &event)); + + /* Initialize the gckEVENT object. */ + event->object.type = gcvOBJ_EVENT; + event->kernel = Kernel; + event->os = os; + event->mutexQueue = gcvNULL; + event->freeList = gcvNULL; + event->freeCount = 0; + event->freeMutex = gcvNULL; + event->list.head = gcvNULL; + event->list.tail = gcvNULL; + event->listMutex = gcvNULL; + event->lastID = 0; + + /* Create the mutexes. */ + gcmkONERROR( + gckOS_CreateMutex(os, &event->mutexQueue)); + + gcmkONERROR( + gckOS_CreateMutex(os, &event->freeMutex)); + + gcmkONERROR( + gckOS_CreateMutex(os, &event->listMutex)); + + /* Create a bunch of event reccords. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; ++i) + { + /* Allocate an event record. */ + gcmkONERROR( + gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), (gctPOINTER *) &record)); + + /* Push it on the free list. */ + record->next = event->freeList; + event->freeList = record; + event->freeCount += 1; + } + + /* Zero out the entire event queue. */ + for (i = 0; i < gcmCOUNTOF(event->queues); ++i) + { + event->queues[i].head = gcvNULL; + } + + /* Zero out the time stamp. */ + event->stamp = 0; + + /* No events to handle. */ + event->pending = 0; + + /* Return pointer to the gckEVENT object. */ + *Event = event; + + /* Success. */ + gcmkFOOTER_ARG("*Event=0x%x", *Event); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (event != gcvNULL) + { + if (event->mutexQueue != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->mutexQueue)); + } + + if (event->freeMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->freeMutex)); + } + + if (event->listMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, event->listMutex)); + } + + while (event->freeList != gcvNULL) + { + record = event->freeList; + event->freeList = record->next; + + gcmkVERIFY_OK(gckOS_Free(os, record)); + } + + gcmkVERIFY_OK(gckOS_Free(os, event)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Destroy +** +** Destroy an gckEVENT object. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ) +{ + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Delete the queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->mutexQueue)); + + /* Free all free events. */ + while (Event->freeList != gcvNULL) + { + record = Event->freeList; + Event->freeList = record->next; + + gcmkVERIFY_OK(gckOS_Free(Event->os, record)); + } + + /* Delete the free mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeMutex)); + + /* Free all pending events. */ + while (Event->list.head != gcvNULL) + { + record = Event->list.head; + Event->list.head = record->next; + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_EVENT, + "Event record 0x%x is still pending for %d.", + record, Event->list.source); + gcmkVERIFY_OK(gckOS_Free(Event->os, record)); + } + + /* Delete the list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->listMutex)); + + /* Mark the gckEVENT object as unknown. */ + Event->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckEVENT object. */ + gcmkVERIFY_OK(gckOS_Free(Event->os, Event)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +static gceSTATUS +gckEVENT_AllocateRecord( + IN gckEVENT Event, + IN gctBOOL AllocateAllowed, + OUT gcsEVENT_PTR * Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctINT i; + gcsEVENT_PTR record; + + gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Test if we are below the allocation threshold. */ + if (AllocateAllowed + && (Event->freeCount < gcdEVENT_MIN_THRESHOLD) + ) + { + /* Allocate a bunch of records. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; ++i) + { + /* Allocate an event record. */ + status = gckOS_Allocate(Event->os, + gcmSIZEOF(gcsEVENT), + (gctPOINTER *) &record); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_EVENT, + "Out of memory allocating event records."); + break; + } + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->freeMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Push it on the free list. */ + record->next = Event->freeList; + Event->freeList = record; + Event->freeCount += 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + } + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeMutex, gcvINFINITE)); + acquired = gcvTRUE; + if (Event->freeCount == 0) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + else + { + *Record = Event->freeList; + Event->freeList = Event->freeList->next; + Event->freeCount -= 1; + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record)); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +gckEVENT_FreeRecord( + IN gckEVENT Event, + IN gcsEVENT_PTR Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Push the record on the free list. */ + Record->next = Event->freeList; + Event->freeList = Record; + Event->freeCount += 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; +} + +static gceSTATUS +gckEVENT_AddList( + IN gckEVENT Event, + IN gcsHAL_INTERFACE_PTR Interface, + IN gceKERNEL_WHERE FromWhere, + IN gctBOOL AllocateAllowed + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsEVENT_PTR record = gcvNULL; + + gcmkHEADER_ARG("Event=0x%x Interface=0x%x FromWhere=%d AllocateAllowed=%d", + Event, Interface, FromWhere, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Interface != gcvNULL); + + switch (FromWhere) + { + case gcvKERNEL_COMMAND: + case gcvKERNEL_PIXEL: + /* Check if the requested source matches the list. */ + if ((Event->list.head != gcvNULL) + && (Event->list.source != FromWhere) + ) + { + /* Just convert to submit from PIXEL. */ + Event->list.source = FromWhere = gcvKERNEL_PIXEL; + } + break; + + default: + /* Invalid argument. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Allocate a free record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record)); + + /* Copy the event interface into the record. */ + gcmkONERROR(gckOS_MemCopy(&record->event, + Interface, + gcmSIZEOF(record->event))); + + gcmkASSERT + ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY) + || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY) + || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY) + || (Interface->command == gcvHAL_WRITE_DATA) + || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY) + || (Interface->command == gcvHAL_SIGNAL) + || (Interface->command == gcvHAL_UNMAP_USER_MEMORY) + ); + + record->next = gcvNULL; + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->listMutex, gcvINFINITE)); + acquired = gcvTRUE; + + if (Event->list.head == gcvNULL) + { + /* List doesn't exist yet. */ + Event->list.head = record; + Event->list.tail = record; + } + else + { + /* Append to the current list. */ + Event->list.tail->next = record; + Event->list.tail = record; + } + + /* Mark the source of this event. */ + Event->list.source = FromWhere; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + } + + if (record != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeNonPagedMemory +** +** Schedule an event to free non-paged memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of non-paged memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of non-paged memory to free. +** +** gctPOINTER Logical +** Logical address of non-paged memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_NON_PAGED_MEMORY; + iface.u.FreeNonPagedMemory.bytes = Bytes; + iface.u.FreeNonPagedMemory.physical = Physical; + iface.u.FreeNonPagedMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeContigiuousMemory +** +** Schedule an event to free contiguous memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of contiguous memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of contiguous memory to free. +** +** gctPOINTER Logical +** Logical address of contiguous memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY; + iface.u.FreeContiguousMemory.bytes = Bytes; + iface.u.FreeContiguousMemory.physical = Physical; + iface.u.FreeContiguousMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeVideoMemory +** +** Schedule an event to free video memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcuVIDMEM_NODE_PTR VideoMemory +** Pointer to a gcuVIDMEM_NODE object to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d", + Event, VideoMemory, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL); + + /* Create an event. */ + iface.command = gcvHAL_FREE_VIDEO_MEMORY; + iface.u.FreeVideoMemory.node = VideoMemory; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Signal +** +** Schedule an event to trigger a signal. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIGNAL Signal +** Pointer to the signal to trigger. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +*/ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d", + Event, Signal, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + /* Mark the event as a signal. */ + iface.command = gcvHAL_SIGNAL; + iface.u.Signal.signal = Signal; +#ifdef __QNXNTO__ + iface.u.Signal.coid = 0; + iface.u.Signal.rcvid = 0; +#else + iface.u.Signal.auxSignal = gcvNULL; + iface.u.Signal.process = gcvNULL; +#endif + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Unlock +** +** Schedule an event to unlock virtual memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory +** to unlock. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +*/ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d", + Event, FromWhere, Node, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + + /* Mark the event as an unlock. */ + iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; + iface.u.UnlockVideoMemory.node = Node; + iface.u.UnlockVideoMemory.type = Type; + iface.u.UnlockVideoMemory.asynchroneous = 0; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN gcsQUEUE_PTR Queue + ) +{ + gceSTATUS status; + gcsQUEUE_PTR record = gcvNULL, next; + + gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Loop while there are records in the queue. */ + while (Queue != gcvNULL) + { + /* Map record into kernel memory. */ + gcmkONERROR(gckOS_MapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) &record)); + + /* Append event record to event queue. */ + gcmkONERROR( + gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE)); + + /* Next record in the queue. */ + next = record->next; + + /* Unmap record from kernel memory. */ + gcmkONERROR( + gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + record = gcvNULL; + + Queue = next; + } + + /* Submit the event list. */ + gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE)); + + /* Success */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (record != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 Data + ) +{ + gcmkHEADER_ARG("Event=0x%x Data=%08x", Event, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Combine current interrupt status with pending flags. */ + Event->pending |= Data; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctINT i; + gcsEVENT_QUEUE * queue; + gctUINT mask = 0; + gctBOOL acquired = gcvFALSE; +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node; +#endif + gctUINT pending; + gctBOOL suspended = gcvFALSE; + gctBOOL empty = gcvFALSE, idle = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + for (;;) + { + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Get current interrupts. */ + pending = Event->pending; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + + if (pending == 0) + { + /* No more pending interrupts - done. */ + break; + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Pending interrupts 0x%08x", pending); + + queue = gcvNULL; + +#if gcdDEBUG + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[i].head != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Queue(%d): stamp=%llu source=%d", + i, + Event->queues[i].stamp, + Event->queues[i].source); + } + } +#endif + + /* Find the oldest pending interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (pending & (1 << i)) + ) + { + if ((queue == gcvNULL) + || (Event->queues[i].stamp < queue->stamp) + ) + { + queue = &Event->queues[i]; + mask = 1 << i; + } + } + } + + if (queue == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_EVENT, + "Interrupts 0x08x are not pending.", pending); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Mark pending interrupts as handled. */ + Event->pending &= ~pending; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + + break; + } + + /* Check whether there is a missed interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (Event->queues[i].stamp < queue->stamp) + && (Event->queues[i].source == queue->source) + ) + { + gcmkTRACE(gcvLEVEL_ERROR, + "Event %d lost (stamp %llu)", + i, Event->queues[i].stamp); + + /* Use this event instead. */ + queue = &Event->queues[i]; + mask = 0; + } + } + + /* Walk all events for this interrupt. */ + while (queue->head != gcvNULL) + { + gcsEVENT_PTR event; +#ifndef __QNXNTO__ + gctPOINTER logical; +#endif + + event = queue->head; + + /* Dispatch on event type. */ + switch (event->event.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + /* Free non-paged memory. */ + status = gckOS_FreeNonPagedMemory( + Event->os, + event->event.u.FreeNonPagedMemory.bytes, + event->event.u.FreeNonPagedMemory.physical, + event->event.u.FreeNonPagedMemory.logical); + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + /* Unmap the user memory. */ + status = gckOS_FreeContiguous( + Event->os, + event->event.u.FreeContiguousMemory.physical, + event->event.u.FreeContiguousMemory.logical, + event->event.u.FreeContiguousMemory.bytes); + break; + + case gcvHAL_FREE_VIDEO_MEMORY: +#ifdef __QNXNTO__ + node = event->event.u.FreeVideoMemory.node; + if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + && (node->VidMem.logical != gcvNULL) + ) + { + gcmkERR_BREAK( + gckKERNEL_UnmapVideoMemory(event->kernel, + node->VidMem.logical, + event->event.pid, + node->VidMem.bytes)); + node->VidMem.logical = gcvNULL; + } +#endif + + /* Free video memory. */ + status = gckVIDMEM_Free(event->event.u.FreeVideoMemory.node); + break; + + case gcvHAL_WRITE_DATA: +#ifndef __QNXNTO__ + /* Convert physical into logical address. */ + gcmkERR_BREAK( + gckOS_MapPhysical(Event->os, + event->event.u.WriteData.address, + gcmSIZEOF(gctUINT32), + &logical)); + + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + logical, + event->event.u.WriteData.data)); + + /* Unmap the physical memory. */ + gcmkERR_BREAK( + gckOS_UnmapPhysical(Event->os, + logical, + gcmSIZEOF(gctUINT32))); +#else + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + (gctPOINTER) + event->event.u.WriteData.address, + event->event.u.WriteData.data)); +#endif + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + /* Unlock. */ + status = gckVIDMEM_Unlock(event->event.u.UnlockVideoMemory.node, + event->event.u.UnlockVideoMemory.type, + gcvNULL); + break; + + case gcvHAL_SIGNAL: +#ifdef __QNXNTO__ + if ((event->event.u.Signal.coid == 0) + && (event->event.u.Signal.rcvid == 0) + ) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + event->event.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + event->event.u.Signal.signal, + event->event.u.Signal.rcvid, + event->event.u.Signal.coid)); + } +#else + /* Set signal. */ + if (event->event.u.Signal.process == gcvNULL) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + event->event.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + event->event.u.Signal.signal, + event->event.u.Signal.process)); + } + + gcmkASSERT(event->event.u.Signal.auxSignal == gcvNULL); +#endif + break; + + case gcvHAL_UNMAP_USER_MEMORY: + /* Unmap the user memory. */ + status = + gckOS_UnmapUserMemory(Event->os, + event->event.u.UnmapUserMemory.memory, + event->event.u.UnmapUserMemory.size, + event->event.u.UnmapUserMemory.info, + event->event.u.UnmapUserMemory.address); + break; + + default: + /* Invalid argument. */ + gcmkFATAL("Unknown event type: %d", event->event.command); + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + + /* Make sure there are no errors generated. */ + gcmkASSERT(gcmNO_ERROR(status)); + + /* Pop the event from the event queue. */ + gcmkONERROR( + gckOS_AcquireMutex(Event->os, Event->mutexQueue, gcvINFINITE)); + acquired = gcvTRUE; + + /* Unlink head from chain. */ + queue->head = event->next; + + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + acquired = gcvFALSE; + + /* Free the event. */ + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, event)); + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Handled interrupt 0x%08x", mask); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterrupt(Event->os)); + suspended = gcvTRUE; + + /* Mark pending interrupt as handled. */ + Event->pending &= ~mask; + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterrupt(Event->os)); + suspended = gcvFALSE; + } + + /* Check whether the event queue is empty. */ + gcmkONERROR(_IsEmpty(Event, &empty)); + + if (empty) + { + /* Query whether the hardware is idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle)); + + if (idle) + { + /* Inform the system of idle GPU. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_IDLE)); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->mutexQueue)); + } + + if (suspended) + { + /* Resume interrupts. */ + gcmkVERIFY_OK(gckOS_ResumeInterrupt(Event->os)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait + ) +{ + gctUINT8 id = 0xFF; + gctSIZE_T bytes; + gctPOINTER buffer; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctBOOL reserved = gcvFALSE; +#if gcdGPU_TIMEOUT + gctUINT32 timer = 0; +#endif + + gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait); + + /* Only process if we have events queued. */ + if (Event->list.head != gcvNULL) + { + for (;;) + { + /* Allocate an event ID. */ + status = _GetEvent(Event, &id, Event->list.source); + + if (gcmIS_ERROR(status)) + { + /* Out of resources? */ + if (Wait && (status == gcvSTATUS_OUT_OF_RESOURCES)) + { + /* Delay a while. */ + gcmkONERROR(gckOS_Delay(Event->os, 1)); + +#if gcdGPU_TIMEOUT + /* Increment the wait timer. */ + timer += 1; + + if (timer == gcdGPU_TIMEOUT) + { + /* Try to call any outstanding events. */ + gcmkONERROR( + gckHARDWARE_Interrupt(Event->kernel->hardware, + gcvTRUE)); + } + else if (timer > gcdGPU_TIMEOUT) + { + /* Broadcast GPU stuck. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_STUCK)); + + /* Bail out. */ + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } +#endif + } + else + { + gcmkONERROR(status); + } + } + else + { + /* Got en event ID. */ + break; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_EVENT, "Using id=%d", id); + + /* Acquire the list mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->listMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Copy event list to event ID queue. */ + Event->queues[id].source = Event->list.source; + Event->queues[id].head = Event->list.head; + + /* Get process ID. */ + gcmkONERROR(gckOS_GetProcessID(&Event->queues[id].processID)); + + /* Mark event list as empty. */ + Event->list.head = gcvNULL; + + /* Release the list mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + acquired = gcvFALSE; + +#if gcdNULL_DRIVER == 2 + /* Notify immediately on infinite hardware. */ + gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id)); + + gcmkONERROR(gckEVENT_Notify(Event, 0)); +#else + /* Get the size of the hardware event. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + gcvNULL, + id, + gcvKERNEL_PIXEL, + &bytes)); + + /* Reserve space in the command queue. */ + gcmkONERROR(gckCOMMAND_Reserve(Event->kernel->command, + bytes, + &buffer, + &bytes)); + reserved = gcvTRUE; + + /* Set the hardware event in the command queue. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + buffer, + id, + Event->queues[id].source, + &bytes)); + + /* Execute the hardware event. */ + gcmkONERROR(gckCOMMAND_Execute(Event->kernel->command, bytes)); + reserved = gcvFALSE; +#endif + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Need to unroll the mutex acquire. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->listMutex)); + } + + if (reserved) + { + /* Need to release the command buffer. */ + gcmkVERIFY_OK(gckCOMMAND_Release(Event->kernel->command)); + } + + if (id != 0xFF) + { + /* Need to unroll the event allocation. */ + Event->queues[id].head = gcvNULL; + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_heap.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_heap.c new file mode 100644 index 0000000..11c15fc --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_heap.c @@ -0,0 +1,1056 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/** +** @file +** gckHEAP object for kernel HAL layer. The heap implemented here is an arena- +** based memory allocation. An arena-based memory heap allocates data quickly +** from specified arenas and reduces memory fragmentation. +** +*/ +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_HEAP + +/******************************************************************************* +***** Structures *************************************************************** +*******************************************************************************/ + +#define gcdIN_USE ((gcskNODE_PTR) ~0) + +typedef struct _gcskNODE * gcskNODE_PTR; +typedef struct _gcskNODE +{ + /* Number of byets in node. */ + gctSIZE_T bytes; + + /* Pointer to next free node, or gcvNULL to mark the node as freed, or + ** gcdIN_USE to mark the node as used. */ + gcskNODE_PTR next; + +#if gcdDEBUG + /* Time stamp of allocation. */ + gctUINT64 timeStamp; +#endif +} +gcskNODE; + +typedef struct _gcskHEAP * gcskHEAP_PTR; +typedef struct _gcskHEAP +{ + /* Linked list. */ + gcskHEAP_PTR next; + gcskHEAP_PTR prev; + + /* Heap size. */ + gctSIZE_T size; + + /* Free list. */ + gcskNODE_PTR freeList; +} +gcskHEAP; + +struct _gckHEAP +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to a gckOS object. */ + gckOS os; + + /* Locking mutex. */ + gctPOINTER mutex; + + /* Allocation parameters. */ + gctSIZE_T allocationSize; + + /* Heap list. */ + gcskHEAP_PTR heap; +#if gcdDEBUG + gctUINT64 timeStamp; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Profile information. */ + gctUINT32 allocCount; + gctUINT64 allocBytes; + gctUINT64 allocBytesMax; + gctUINT64 allocBytesTotal; + gctUINT32 heapCount; + gctUINT32 heapCountMax; + gctUINT64 heapMemory; + gctUINT64 heapMemoryMax; +#endif +}; + +/******************************************************************************* +***** Static Support Functions ************************************************* +*******************************************************************************/ + +#if gcdDEBUG +static gctSIZE_T +_DumpHeap( + IN gcskHEAP_PTR Heap + ) +{ + gctPOINTER p; + gctSIZE_T leaked = 0; + + /* Start at first node. */ + for (p = Heap + 1;;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + /* Check if this is a used node. */ + if (node->next == gcdIN_USE) + { + /* Print the leaking node. */ + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_HEAP, + "Detected leaking: node=0x%x bytes=%lu timeStamp=%llu " + "(%08X %c%c%c%c)", + node, node->bytes, node->timeStamp, + ((gctUINT32_PTR) (node + 1))[0], + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[0]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[1]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[2]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[3])); + + /* Add leaking byte count. */ + leaked += node->bytes; + } + + /* Test for end of heap. */ + if (node->bytes == 0) + { + break; + } + + else + { + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + } + + /* Return the number of leaked bytes. */ + return leaked; +} +#endif + +static gceSTATUS +_CompactKernelHeap( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap, next; + gctPOINTER p; + gcskHEAP_PTR freeList = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = next) + { + gcskNODE_PTR lastFree = gcvNULL; + + /* Zero out the free list. */ + heap->freeList = gcvNULL; + + /* Start at the first node. */ + for (p = (gctUINT8_PTR) (heap + 1);;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + gcmkASSERT(p <= (gctPOINTER) ((gctUINT8_PTR) (heap + 1) + heap->size)); + + /* Test if this node not used. */ + if (node->next != gcdIN_USE) + { + /* Test if this is the end of the heap. */ + if (node->bytes == 0) + { + break; + } + + /* Test of this is the first free node. */ + else if (lastFree == gcvNULL) + { + /* Initialzie the free list. */ + heap->freeList = node; + lastFree = node; + } + + else + { + /* Test if this free node is contiguous with the previous + ** free node. */ + if ((gctUINT8_PTR) lastFree + lastFree->bytes == p) + { + /* Just increase the size of the previous free node. */ + lastFree->bytes += node->bytes; + } + else + { + /* Add to linked list. */ + lastFree->next = node; + lastFree = node; + } + } + } + + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + + /* Mark the end of the chain. */ + if (lastFree != gcvNULL) + { + lastFree->next = gcvNULL; + } + + /* Get next heap. */ + next = heap->next; + + /* Check if the entire heap is free. */ + if ((heap->freeList != gcvNULL) + && (heap->freeList->bytes == heap->size - gcmSIZEOF(gcskNODE)) + ) + { + /* Remove the heap from the linked list. */ + if (heap->prev == gcvNULL) + { + Heap->heap = next; + } + else + { + heap->prev->next = next; + } + + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profiling. */ + Heap->heapCount -= 1; + Heap->heapMemory -= heap->size + gcmSIZEOF(gcskHEAP); +#endif + + /* Add this heap to the list of heaps that need to be freed. */ + heap->next = freeList; + freeList = heap; + } + } + + if (freeList != gcvNULL) + { + /* Release the mutex, remove any chance for a dead lock. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Free all heaps in the free list. */ + for (heap = freeList; heap != gcvNULL; heap = next) + { + /* Get pointer to the next heap. */ + next = heap->next; + + /* Free the heap. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Freeing heap 0x%x (%lu bytes)", + heap, heap->size + gcmSIZEOF(gcskHEAP)); + gcmkVERIFY_OK(gckOS_FreeVirtualMemory(Heap->os, heap)); + } + + /* Acquire the mutex again. */ + gcmkVERIFY_OK( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +***** gckHEAP API Code ********************************************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckHEAP_Construct +** +** Construct a new gckHEAP object. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctSIZE_T AllocationSize +** Minimum size per arena. +** +** OUTPUT: +** +** gckHEAP * Heap +** Pointer to a variable that will hold the pointer to the gckHEAP +** object. +*/ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ) +{ + gceSTATUS status; + gckHEAP heap = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Heap != gcvNULL); + + /* Allocate the gckHEAP object. */ + gcmkONERROR( + gckOS_AllocateMemory(Os, + gcmSIZEOF(struct _gckHEAP), + (gctPOINTER *) &heap)); + + /* Initialize the gckHEAP object. */ + heap->object.type = gcvOBJ_HEAP; + heap->os = Os; + heap->allocationSize = AllocationSize; + heap->heap = gcvNULL; +#if gcdDEBUG + heap->timeStamp = 0; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Zero the counters. */ + heap->allocCount = 0; + heap->allocBytes = 0; + heap->allocBytesMax = 0; + heap->allocBytesTotal = 0; + heap->heapCount = 0; + heap->heapCountMax = 0; + heap->heapMemory = 0; + heap->heapMemoryMax = 0; +#endif + + /* Create the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex)); + + /* Return the pointer to the gckHEAP object. */ + *Heap = heap; + + /* Success. */ + gcmkFOOTER_ARG("*Heap=0x%x", Heap); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (heap != gcvNULL) + { + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Destroy +** +** Destroy a gckHEAP object. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap; +#if gcdDEBUG + gctSIZE_T leaked = 0; +#endif + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap) + { + /* Unlink heap from linked list. */ + Heap->heap = heap->next; + +#if gcdDEBUG + /* Check for leaked memory. */ + leaked += _DumpHeap(heap); +#endif + + /* Free the heap. */ + gcmkVERIFY_OK(gckOS_FreeVirtualMemory(Heap->os, heap)); + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex)); + + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap)); + + /* Success. */ +#if gcdDEBUG + gcmkFOOTER_ARG("leaked=%lu", leaked); +#else + gcmkFOOTER_NO(); +#endif + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHEAP_Allocate +** +** Allocate data from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the address of the allocated +** memory. +*/ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctBOOL acquired = gcvFALSE; + gcskHEAP_PTR heap; + gceSTATUS status; + gctSIZE_T bytes; + gcskNODE_PTR node, used, prevFree = gcvNULL; + gctPOINTER memory = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Determine number of bytes required for a node. */ + bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Check if this allocation is bigger than the default allocation size. */ + if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP)) + { + /* Adjust allocation size. */ + Heap->allocationSize = bytes * 2; + } + + else if (Heap->heap != gcvNULL) + { + gctINT i; + + /* 2 retries, since we might need to compact. */ + for (i = 0; i < 2; ++i) + { + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = heap->next) + { + /* Check if this heap has enough bytes to hold the request. */ + if (bytes < heap->size) + { + prevFree = gcvNULL; + + /* Walk the chain of free nodes. */ + for (node = heap->freeList; + node != gcvNULL; + node = node->next + ) + { + gcmkASSERT(node->next != gcdIN_USE); + + /* Check if this free node has enough bytes. */ + if (node->bytes >= bytes) + { + /* Use the node. */ + goto UseNode; + } + + /* Save current free node for linked list management. */ + prevFree = node; + } + } + } + + if (i == 0) + { + /* Compact the heap. */ + gcmkVERIFY_OK(_CompactKernelHeap(Heap)); + +#if gcdDEBUG + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "===== KERNEL HEAP ====="); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of allocations : %12u", + Heap->allocCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of bytes allocated : %12llu", + Heap->allocBytes); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum allocation size : %12llu", + Heap->allocBytesMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Total number of bytes allocated : %12llu", + Heap->allocBytesTotal); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of heaps : %12u", + Heap->heapCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Heap memory in bytes : %12llu", + Heap->heapMemory); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum number of heaps : %12u", + Heap->heapCountMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum heap memory in bytes : %12llu", + Heap->heapMemoryMax); +#endif + } + } + } + + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + acquired = gcvFALSE; + + /* Allocate a new heap. */ + gcmkONERROR( + gckOS_AllocateVirtualMemory(Heap->os, + Heap->allocationSize, + &memory)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Allocated heap 0x%x (%lu bytes)", + memory, Heap->allocationSize); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Use the allocated memory as the heap. */ + heap = (gcskHEAP_PTR) memory; + + /* Insert this heap to the head of the chain. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP); + + if (heap->next != gcvNULL) + { + heap->next->prev = heap; + } + Heap->heap = heap; + + /* Mark the end of the heap. */ + node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap + + Heap->allocationSize + - gcmSIZEOF(gcskNODE) + ); + node->bytes = 0; + node->next = gcvNULL; + + /* Create a free list. */ + node = (gcskNODE_PTR) (heap + 1); + heap->freeList = node; + + /* Initialize the free list. */ + node->bytes = heap->size - gcmSIZEOF(gcskNODE); + node->next = gcvNULL; + + /* No previous free. */ + prevFree = gcvNULL; + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profiling. */ + Heap->heapCount += 1; + Heap->heapMemory += Heap->allocationSize; + + if (Heap->heapCount > Heap->heapCountMax) + { + Heap->heapCountMax = Heap->heapCount; + } + if (Heap->heapMemory > Heap->heapMemoryMax) + { + Heap->heapMemoryMax = Heap->heapMemory; + } +#endif + +UseNode: + /* Verify some stuff. */ + gcmkASSERT(heap != gcvNULL); + gcmkASSERT(node != gcvNULL); + gcmkASSERT(node->bytes >= bytes); + + if (heap->prev != gcvNULL) + { + /* Unlink the heap from the linked list. */ + heap->prev->next = heap->next; + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + + /* Move the heap to the front of the list. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + Heap->heap = heap; + heap->next->prev = heap; + } + + /* Check if there is enough free space left after usage for another free + ** node. */ + if (node->bytes - bytes >= gcmSIZEOF(gcskNODE)) + { + /* Allocated used space from the back of the free list. */ + used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes); + + /* Adjust the number of free bytes. */ + node->bytes -= bytes; + gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE)); + } + else + { + /* Remove this free list from the chain. */ + if (prevFree == gcvNULL) + { + heap->freeList = node->next; + } + else + { + prevFree->next = node->next; + } + + /* Consume the entire free node. */ + used = (gcskNODE_PTR) node; + bytes = node->bytes; + } + + /* Mark node as used. */ + used->bytes = bytes; + used->next = gcdIN_USE; +#if gcdDEBUG + used->timeStamp = ++Heap->timeStamp; +#endif + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profile counters. */ + Heap->allocCount += 1; + Heap->allocBytes += bytes; + Heap->allocBytesMax = gcmMAX(Heap->allocBytes, Heap->allocBytesMax); + Heap->allocBytesTotal += bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Return pointer to memory. */ + *Memory = used + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + } + + if (memory != gcvNULL) + { + /* Free the heap memory. */ + gckOS_FreeVirtualMemory(Heap->os, memory); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Free +** +** Free allocated memory from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctPOINTER Memory +** Pointer to memory to free. +** +** OUTPUT: +** +** NOTHING. +*/ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Memory + ) +{ + gcskNODE_PTR node; + gceSTATUS status; + + gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + /* Pointer to structure. */ + node = (gcskNODE_PTR) Memory - 1; + + /* Mark the node as freed. */ + node->next = gcvNULL; + +#if VIVANTE_PROFILER || gcdDEBUG + /* Update profile counters. */ + Heap->allocBytes -= node->bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ) +{ + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + + /* Zero the counters. */ + Heap->allocCount = 0; + Heap->allocBytes = 0; + Heap->allocBytesMax = 0; + Heap->allocBytesTotal = 0; + Heap->heapCount = 0; + Heap->heapCountMax = 0; + Heap->heapMemory = 0; + Heap->heapMemoryMax = 0; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +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; +} +#endif /* VIVANTE_PROFILER */ + +/******************************************************************************* +***** Test Code **************************************************************** +*******************************************************************************/ + +#if defined gcdHAL_TEST + +#include <stdlib.h> +#define gcmRANDOM(n) (rand() % n) + +typedef struct +{ + gctSIZE_T bytes; + gctPOINTER memory; +} +gcskHEAP_TEST; + +gceSTATUS +gckHEAP_Test( + IN gckHEAP Heap, + IN gctSIZE_T Vectors, + IN gctSIZE_T MaxSize + ) +{ + gctSIZE_T nodeCount = MaxSize / 4; + gcskHEAP_TEST * nodes = gcvNULL; + gctSIZE_T bytes, index, i; + gceSTATUS status, failure = gcvSTATUS_OK; + gctUINT8_PTR memory; + gcskHEAP_PTR heap, current; + + /* Allocate the node array. */ + gcmkONERROR( + gckOS_AllocateMemory(Heap->os, + nodeCount * gcmSIZEOF(gcskHEAP_TEST), + (gctPOINTER *) &nodes)); + + /* Mark all nodes as free. */ + gcmkONERROR( + gckOS_ZeroMemory(nodes, nodeCount * gcmSIZEOF(gcskHEAP_TEST))); + + gcmkONERROR(gckHEAP_ProfileStart(Heap)); + + /* Loop through all vectors. */ + while (Vectors-- > 0) + { + /* Get a random index. */ + index = gcmRANDOM(nodeCount); + + /* Test if we need to allocate pages. */ + if (nodes[index].bytes == 0) + { + /* Generate a random byte size. */ + do + { + bytes = gcmALIGN(gcmRANDOM(MaxSize), gcmSIZEOF(gctSIZE_T)); + } + while (bytes == 0); + + /* Allocate pages. */ + status = gckHEAP_Allocate(Heap, bytes, (gctPOINTER *) &memory); + + if (gcmIS_SUCCESS(status)) + { + /* Mark node as allocated. */ + nodes[index].bytes = bytes; + nodes[index].memory = memory; + + /* Put signature in the memory. */ + for (i = 0; i < bytes; i += gcmSIZEOF(gctSIZE_T)) + { + *(gctSIZE_T_PTR) (memory + i) = index; + } + } + else + { + gcmkTRACE(gcvLEVEL_WARNING, + "%s(%d): Failed to allocate %lu bytes", + __FUNCTION__, __LINE__, bytes); + } + } + else + { + /* Verify the memory. */ + memory = nodes[index].memory; + for (i = 0; i < nodes[index].bytes; i += gcmSIZEOF(gctSIZE_T)) + { + if (*(gctSIZE_T_PTR) (memory + i) != index) + { + gcmkFATAL("%s(%d): Corruption detected at index %lu", + __FUNCTION__, __LINE__, index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the memory. */ + status = gckHEAP_Free(Heap, memory); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("%s(%d): Cannot free %lu bytes at 0x%x (index=%lu)", + __FUNCTION__, __LINE__, + nodes[index].bytes, memory, index); + + failure = status; + } + + /* Mark the node as free. */ + nodes[index].bytes = 0; + } + + /* Verify the heap chain. */ + i = 0; + for (current = Heap->heap; current != gcvNULL; current = current->next) + { + gctSIZE_T j; + for (heap = Heap->heap, j = 0; j < i; heap = heap->next, ++j) + { + if (heap == current) + { + gcmkFATAL("%s(%d): Linked list corrupted for heap 0x%x", + __FUNCTION__, __LINE__, current); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + if (heap != current) + { + gcmkFATAL("%s(%d): Linked list corrupted for heap 0x%x", + __FUNCTION__, __LINE__, current); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + + ++i; + } + } + + /* Walk the entire array of nodes. */ + for (index = 0; index < nodeCount; ++index) + { + /* Test if we need to free pages. */ + if (nodes[index].bytes != 0) + { + /* Verify the memory. */ + memory = nodes[index].memory; + for (i = 0; i < nodes[index].bytes; i += gcmSIZEOF(gctSIZE_T)) + { + if (*(gctSIZE_T_PTR) (memory + i) != index) + { + gcmkFATAL("%s(%d): Corruption detected at page %lu", + __FUNCTION__, __LINE__, index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the memory. */ + status = gckHEAP_Free(Heap, memory); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("%s(%d): Cannot free %u bytes at 0x%x (index=%lu)", + __FUNCTION__, __LINE__, + nodes[index].bytes, memory, index); + + failure = status; + } + } + } + + /* Perform garbage collection. */ + gcmkONERROR(_CompactKernelHeap(Heap)); + + /* Show profiling. */ + gcmkONERROR(gckHEAP_ProfileEnd(Heap, "Profile")); + + /* Verify we did not loose any nodes. */ + if (Heap->heap != gcvNULL) + { + gcmkFATAL("%s(%d): Detected leaking in the heap.", + __FUNCTION__, __LINE__); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + +OnError: + /* Roll back. */ + if (nodes != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeMemory(Heap->os, nodes)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_mmu.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_mmu.c new file mode 100644 index 0000000..56b1522 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_mmu.c @@ -0,0 +1,928 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_MMU + +typedef enum _gceMMU_TYPE +{ + gcvMMU_USED = 0, + gcvMMU_SINGLE, + gcvMMU_FREE, +} +gceMMU_TYPE; + +static gceSTATUS +_Link( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Next + ) +{ + if (Index >= Mmu->pageTableEntries) + { + /* Just move heap pointer. */ + Mmu->heapList = Next; + } + else + { + /* Address page table. */ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + /* Dispatch on node type. */ + switch (pageTable[Index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Set single index. */ + pageTable[Index] = (Next << 8) | gcvMMU_SINGLE; + break; + + case gcvMMU_FREE: + /* Set index. */ + pageTable[Index + 1] = Next; + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", Index); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_AddFree( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Node, + IN gctUINT32 Count + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + if (Count == 1) + { + /* Initialize a single page node. */ + pageTable[Node] = (~0U << 8) | gcvMMU_SINGLE; + } + else + { + /* Initialize the node. */ + pageTable[Node + 0] = (Count << 8) | gcvMMU_FREE; + pageTable[Node + 1] = ~0U; + } + + /* Append the node. */ + return _Link(Mmu, Index, Node); +} + +static gceSTATUS +_Collect( + IN gckMMU Mmu + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + gceSTATUS status; + gctUINT32 i, previous, start = 0, count = 0; + + /* Flush the MMU cache. */ + gcmkONERROR( + gckHARDWARE_FlushMMU(Mmu->hardware)); + + previous = Mmu->heapList = ~0U; + Mmu->freeNodes = gcvFALSE; + + /* Walk the entire page table. */ + for (i = 0; i < Mmu->pageTableEntries; ++i) + { + /* Dispatch based on type of page. */ + switch (pageTable[i] & 0xFF) + { + case gcvMMU_USED: + /* Used page, so close any open node. */ + if (count > 0) + { + /* Add the node. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + + /* Reset the node. */ + previous = start; + count = 0; + } + break; + + case gcvMMU_SINGLE: + /* Single free node. */ + if (count++ == 0) + { + /* Start a new node. */ + start = i; + } + break; + + case gcvMMU_FREE: + /* A free node. */ + if (count == 0) + { + /* Start a new node. */ + start = i; + } + + /* Advance the count. */ + count += pageTable[i] >> 8; + + /* Advance the index into the page table. */ + i += (pageTable[i] >> 8) - 1; + break; + + default: + gcmkFATAL("MMU page table correcupted at index %u!", i); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* See if we have an open node left. */ + if (count > 0) + { + /* Add the node to the list. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU, + "Performed a garbage collection of the MMU heap."); + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + /* Return the staus. */ + return status; +} + +/******************************************************************************* +** +** gckMMU_Construct +** +** Construct a new gckMMU object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T MmuSize +** Number of bytes for the page table. +** +** OUTPUT: +** +** gckMMU * Mmu +** Pointer to a variable that receives the gckMMU object pointer. +*/ +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ) +{ + gckOS os; + gckHARDWARE hardware; + gceSTATUS status; + gckMMU mmu = gcvNULL; + gctUINT32_PTR pageTable; + + gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(MmuSize > 0); + gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Extract the gckHARDWARE object pointer. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Allocate memory for the gckMMU object. */ + gcmkONERROR( + gckOS_Allocate(os, sizeof(struct _gckMMU), (gctPOINTER *) &mmu)); + + /* Initialize the gckMMU object. */ + mmu->object.type = gcvOBJ_MMU; + mmu->os = os; + mmu->hardware = hardware; + mmu->pageTableMutex = gcvNULL; + mmu->pageTableLogical = gcvNULL; +#ifdef __QNXNTO__ + mmu->nodeList = gcvNULL; + mmu->nodeMutex = gcvNULL; +#endif + + /* Create the page table mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex)); + +#ifdef __QNXNTO__ + /* Create the node list mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->nodeMutex)); +#endif + + /* Allocate the page table (not more than 256 kB). */ + mmu->pageTableSize = gcmMIN(MmuSize, 256 << 10); + gcmkONERROR( + gckOS_AllocateContiguous(os, + gcvFALSE, + &mmu->pageTableSize, + &mmu->pageTablePhysical, + (gctPOINTER *) &mmu->pageTableLogical)); + + /* Compute number of entries in page table. */ + mmu->pageTableEntries = mmu->pageTableSize / sizeof(gctUINT32); + + /* Mark all pages as free. */ + pageTable = mmu->pageTableLogical; + pageTable[0] = (mmu->pageTableEntries << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + mmu->heapList = 0; + mmu->freeNodes = gcvFALSE; + + /* Set page table address. */ + gcmkONERROR( + gckHARDWARE_SetMMU(hardware, (gctPOINTER) mmu->pageTableLogical)); + + /* Return the gckMMU object pointer. */ + *Mmu = mmu; + + /* Success. */ + gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (mmu != gcvNULL) + { + if (mmu->pageTableLogical != gcvNULL) + { + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(os, + mmu->pageTablePhysical, + (gctPOINTER) mmu->pageTableLogical, + mmu->pageTableSize)); + } + + if (mmu->pageTableMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->pageTableMutex)); + } + +#ifdef __QNXNTO__ + if (mmu->nodeMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->nodeMutex)); + } +#endif + + /* Mark the gckMMU object as unknown. */ + mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the allocates memory. */ + gcmkVERIFY_OK(gckOS_Free(os, mmu)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckMMU_Destroy +** +** Destroy a gckMMU object. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ) +{ +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node, next; +#endif + + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + +#ifdef __QNXNTO__ + /* Free all associated virtual memory. */ + for (node = Mmu->nodeList; node != gcvNULL; node = next) + { + next = node->Virtual.next; + gcmkVERIFY_OK(gckVIDMEM_Free(node, gcvNULL)); + } +#endif + + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + Mmu->pageTablePhysical, + (gctPOINTER) Mmu->pageTableLogical, + Mmu->pageTableSize)); + +#ifdef __QNXNTO__ + /* Delete the node list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->nodeMutex)); +#endif + + /* Delete the page table mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Mark the gckMMU object as unknown. */ + Mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckMMU object. */ + gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckMMU_AllocatePages +** +** Allocate pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctSIZE_T PageCount +** Number of pages to allocate. +** +** OUTPUT: +** +** gctPOINTER * PageTable +** Pointer to a variable that receives the base address of the page +** table. +** +** gctUINT32 * Address +** Pointer to a variable that receives the hardware specific address. +*/ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gctUINT32 index = 0, previous = ~0U, left; + gctUINT32_PTR pageTable; + gctBOOL gotIt; + gctUINT32 address; + + gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + + if (PageCount > Mmu->pageTableEntries) + { + /* Not enough pages avaiable. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Cast pointer to page table. */ + for (pageTable = Mmu->pageTableLogical, gotIt = gcvFALSE; !gotIt;) + { + /* Walk the heap list. */ + for (index = Mmu->heapList; !gotIt && (index < Mmu->pageTableEntries);) + { + /* Check the node type. */ + switch (pageTable[index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Single odes are valid if we only need 1 page. */ + if (PageCount == 1) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index] >> 8; + } + break; + + case gcvMMU_FREE: + /* Test if the node has enough space. */ + if (PageCount <= (pageTable[index] >> 8)) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index + 1]; + } + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", index); + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + + /* Test if we are out of memory. */ + if (index >= Mmu->pageTableEntries) + { + if (Mmu->freeNodes) + { + /* Time to move out the trash! */ + gcmkONERROR(_Collect(Mmu)); + } + else + { + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + } + + switch (pageTable[index] & 0xFF) + { + case gcvMMU_SINGLE: + /* Unlink single node from free list. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index] >> 8)); + break; + + case gcvMMU_FREE: + /* Check how many pages will be left. */ + left = (pageTable[index] >> 8) - PageCount; + switch (left) + { + case 0: + /* The entire node is consumed, just unlink it. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index + 1])); + break; + + case 1: + /* One page will remain. Convert the node to a single node and + ** advance the index. */ + pageTable[index] = (pageTable[index + 1] << 8) | gcvMMU_SINGLE; + index ++; + break; + + default: + /* Enough pages remain for a new node. However, we will just adjust + ** the size of the current node and advance the index. */ + pageTable[index] = (left << 8) | gcvMMU_FREE; + index += left; + break; + } + break; + } + + /* Mark node as used. */ + pageTable[index] = gcvMMU_USED; + + /* Return pointer to page table. */ + *PageTable = &pageTable[index]; + + /* Build virtual address. */ + gcmkONERROR( + gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address)); + + if (Address != gcvNULL) + { + *Address = address; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x", + *PageTable, gcmOPT_VALUE(Address)); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckMMU_FreePages +** +** Free pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctPOINTER PageTable +** Base address of the page table to free. +** +** gctSIZE_T PageCount +** Number of pages to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ) +{ + gctUINT32_PTR pageTable; + + gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu", + Mmu, PageTable, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + + /* Convert the pointer. */ + pageTable = (gctUINT32_PTR) PageTable; + + if (PageCount == 1) + { + /* Single page node. */ + pageTable[0] = (~0U << 8) | gcvMMU_SINGLE; + } + else + { + /* Mark the node as free. */ + pageTable[0] = (PageCount << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + } + + /* We have free nodes. */ + Mmu->freeNodes = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + Node->Virtual.next = Mmu->nodeList; + Mmu->nodeList = Node; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR *iter; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + for (iter = &Mmu->nodeList; *iter; iter = &(*iter)->Virtual.next) + { + if (*iter == Node) + { + *iter = Node->Virtual.next; + break; + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckMMU Mmu, + IN gctHANDLE Handle + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcuVIDMEM_NODE_PTR curr, next; + + gcmkHEADER_ARG("Mmu=0x%x Handle=0x%x", Mmu, Handle); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + for (curr = Mmu->nodeList; curr != gcvNULL; curr = next) + { + next = curr->Virtual.next; + + if (curr->Virtual.handle == Handle) + { + while (curr->Virtual.locked > 0 || curr->Virtual.unlockPending) + { + gcmkONERROR(gckVIDMEM_Unlock(curr, gcvSURF_TYPE_UNKNOWN, gcvNULL, gcvNULL)); + } + + gcmkVERIFY_OK(gckVIDMEM_Free(curr, gcvNULL)); + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +/****************************************************************************** +****************************** T E S T C O D E ****************************** +******************************************************************************/ + +#if defined gcdHAL_TEST + +#include <stdlib.h> +#define gcmRANDOM(n) (rand() % n) + +typedef struct +{ + gctSIZE_T pageCount; + gctUINT32_PTR pageTable; +} +gcsMMU_TEST; + +gceSTATUS +gckMMU_Test( + IN gckMMU Mmu, + IN gctSIZE_T Vectors, + IN gctINT MaxSize + ) +{ + const gctINT nodeCount = MaxSize / 4; + gcsMMU_TEST * nodes = gcvNULL; + gceSTATUS status, failure = gcvSTATUS_OK; + gctSIZE_T i, count; + gctUINT32_PTR pageTable; + gctINT index; + + /* Allocate the node array. */ + gcmkONERROR( + gckOS_Allocate(Mmu->os, + nodeCount * gcmSIZEOF(gcsMMU_TEST), + (gctPOINTER *) &nodes)); + + /* Mark all nodes as free. */ + gcmkONERROR( + gckOS_ZeroMemory(nodes, nodeCount * gcmSIZEOF(gcsMMU_TEST))); + + /* Loop through all vectors. */ + while (Vectors-- > 0) + { + /* Get a random index. */ + index = gcmRANDOM(nodeCount); + + /* Test if we need to allocate pages. */ + if (nodes[index].pageCount == 0) + { + /* Generate a random page count. */ + do + { + count = gcmRANDOM(MaxSize); + } + while (count == 0); + + /* Allocate pages. */ + status = gckMMU_AllocatePages(Mmu, + count, + (gctPOINTER *) &pageTable, + gcvNULL); + + if (gcmIS_SUCCESS(status)) + { + /* Mark node as allocated. */ + nodes[index].pageCount = count; + nodes[index].pageTable = pageTable; + + /* Put signature in the page table. */ + for (i = 0; i < count; ++i) + { + pageTable[i] = (index << 8) | gcvMMU_USED; + } + } + else + { + gcmkTRACE(gcvLEVEL_WARNING, + "gckMMU_Test: Failed to allocate %u pages", + count); + } + } + else + { + /* Verify the page table. */ + pageTable = nodes[index].pageTable; + for (i = 0; i < nodes[index].pageCount; ++i) + { + if (pageTable[i] != ((index << 8) | gcvMMU_USED)) + { + gcmkFATAL("gckMMU_Test: Corruption detected at page %u", + index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the pages. */ + status = gckMMU_FreePages(Mmu, pageTable, nodes[index].pageCount); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("gckMMU_Test: Cannot free %u pages at 0x%x (index=%u)", + nodes[index].pageCount, pageTable, index); + + failure = status; + } + + /* Mark the node as free. */ + nodes[index].pageCount = 0; + } + } + + /* Walk the entire array of nodes. */ + for (index = 0; index < nodeCount; ++index) + { + /* Test if we need to free pages. */ + if (nodes[index].pageCount != 0) + { + /* Verify the page table. */ + pageTable = nodes[index].pageTable; + for (i = 0; i < nodes[index].pageCount; ++i) + { + if (pageTable[i] != ((index << 8) | gcvMMU_USED)) + { + gcmkFATAL("gckMMU_Test: Corruption detected at page %u", + index); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Free the pages. */ + status = gckMMU_FreePages(Mmu, pageTable, nodes[index].pageCount); + + if (gcmIS_ERROR(status)) + { + gcmkFATAL("gckMMU_Test: Cannot free %u pages at 0x%x (index=%u)", + nodes[index].pageCount, pageTable, index); + + failure = status; + } + } + } + + /* Perform garbage collection. */ + gcmkONERROR(_Collect(Mmu)); + + /* Verify we did not loose any nodes. */ + if ((Mmu->heapList != 0) + || ((Mmu->pageTableLogical[0] & 0xFF) != gcvMMU_FREE) + || (Mmu->pageTableEntries != (Mmu->pageTableLogical[0] >> 8)) + ) + { + gcmkFATAL("gckMMU_Test: Detected leaking in the page table."); + + failure = gcvSTATUS_HEAP_CORRUPTED; + } + +OnError: + /* Free the array of nodes. */ + if (nodes != gcvNULL) + { + gcmkVERIFY_OK(gckOS_Free(Mmu->os, nodes)); + } + + /* Return test status. */ + return failure; +} +#endif + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_precomp.h b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_precomp.h new file mode 100644 index 0000000..efe0823 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_precomp.h @@ -0,0 +1,32 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_precomp_h_ +#define __gc_hal_kernel_precomp_h_ + +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" + +#endif /* __gc_hal_kernel_precomp_h_ */ + diff --git a/kernel_drivers/v2/hal/kernel/gc_hal_kernel_video_memory.c b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_video_memory.c new file mode 100644 index 0000000..1f04390 --- /dev/null +++ b/kernel_drivers/v2/hal/kernel/gc_hal_kernel_video_memory.c @@ -0,0 +1,1754 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_VIDMEM + +/******************************************************************************\ +******************************* Private Functions ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** _Split +** +** Split a node on the required byte boundary. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the node to split. +** +** gctSIZE_T Bytes +** Number of bytes to keep in the node. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gctBOOL +** gcvTRUE if the node was split successfully, or gcvFALSE if there is an +** error. +** +*/ +static gctBOOL +_Split( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctSIZE_T Bytes + ) +{ + gcuVIDMEM_NODE_PTR node; + + /* Make sure the byte boundary makes sense. */ + if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes)) + { + return gcvFALSE; + } + + /* Allocate a new gcuVIDMEM_NODE object. */ + if (gcmIS_ERROR(gckOS_Allocate(Os, + gcmSIZEOF(gcuVIDMEM_NODE), + (gctPOINTER *) &node))) + { + /* Error. */ + return gcvFALSE; + } + + /* Initialize gcuVIDMEM_NODE structure. */ + node->VidMem.offset = Node->VidMem.offset + Bytes; + node->VidMem.bytes = Node->VidMem.bytes - Bytes; + node->VidMem.alignment = 0; + node->VidMem.locked = 0; + node->VidMem.memory = Node->VidMem.memory; + node->VidMem.pool = Node->VidMem.pool; + node->VidMem.physical = Node->VidMem.physical; +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = 0; +#endif + + /* Insert node behind specified node. */ + node->VidMem.next = Node->VidMem.next; + node->VidMem.prev = Node; + Node->VidMem.next = node->VidMem.next->VidMem.prev = node; + + /* Insert free node behind specified node. */ + node->VidMem.nextFree = Node->VidMem.nextFree; + node->VidMem.prevFree = Node; + Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node; + + /* Adjust size of specified node. */ + Node->VidMem.bytes = Bytes; + + /* Success. */ + return gcvTRUE; +} + +/******************************************************************************* +** +** _Merge +** +** Merge two adjacent nodes together. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the first of the two nodes to merge. +** +** OUTPUT: +** +** Nothing. +** +*/ +static gceSTATUS +_Merge( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gcuVIDMEM_NODE_PTR node; + + /* Save pointer to next node. */ + node = Node->VidMem.next; + + /* This is a good time to make sure the heap is not corrupted. */ + if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset) + { + /* Corrupted heap. */ + gcmkASSERT( + Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset); + return gcvSTATUS_HEAP_CORRUPTED; + } + + /* Adjust byte count. */ + Node->VidMem.bytes += node->VidMem.bytes; + + /* Unlink next node from linked list. */ + Node->VidMem.next = node->VidMem.next; + Node->VidMem.nextFree = node->VidMem.nextFree; + + Node->VidMem.next->VidMem.prev = + Node->VidMem.nextFree->VidMem.prevFree = Node; + + /* Free next node. */ + return gckOS_Free(Os, node); +} + +/******************************************************************************\ +******************************* gckVIDMEM API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckVIDMEM_ConstructVirtual +** +** Construct a new gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer. +*/ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gckOS os; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x Bytes=%lu", Kernel, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate an gcuVIDMEM_NODE union. */ + gcmkONERROR( + gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), (gctPOINTER *) &node)); + + /* Initialize gcuVIDMEM_NODE union for virtual memory. */ + node->Virtual.kernel = Kernel; + node->Virtual.contiguous = Contiguous; + node->Virtual.locked = 0; + node->Virtual.logical = gcvNULL; + node->Virtual.pageTable = gcvNULL; + node->Virtual.mutex = gcvNULL; +#ifdef __QNXNTO__ + node->Virtual.next = gcvNULL; + node->Virtual.unlockPending = gcvFALSE; + node->Virtual.freePending = gcvFALSE; + node->Virtual.handle = Handle; +#else + node->Virtual.pending = gcvFALSE; +#endif + + /* Create the mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &node->Virtual.mutex)); + + /* Allocate the virtual memory. */ + gcmkONERROR( + gckOS_AllocatePagedMemoryEx(os, + node->Virtual.contiguous, + node->Virtual.bytes = Bytes, + &node->Virtual.physical)); + +#ifdef __QNXNTO__ + /* Register. */ + gckMMU_InsertNode(Kernel->mmu, node); +#endif + + /* Return pointer to the gcuVIDMEM_NODE union. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Created virtual node 0x%x for %u bytes @ 0x%x", + node, Bytes, node->Virtual.physical); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (node != gcvNULL) + { + if (node->Virtual.mutex != gcvNULL) + { + /* Destroy the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->Virtual.mutex)); + } + + /* Free the structure. */ + gcmkVERIFY_OK(gckOS_Free(os, node)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_DestroyVirtual +** +** Destroy an gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gckOS os; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extact the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + +#ifdef __QNXNTO__ + /* Unregister. */ + gcmkVERIFY_OK( + gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node)); + + /* Free virtual memory. */ + gcmkVERIFY_OK( + gckOS_FreePagedMemory(os, + Node->Virtual.physical, + Node->Virtual.bytes)); +#endif + + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex)); + + if (Node->Virtual.pageTable != gcvNULL) + { + /* Free the pages. */ + gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + } + + /* Delete the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckOS_Free(os, Node)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Construct +** +** Construct a new gckVIDMEM object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 BaseAddress +** Base address for the video memory heap. +** +** gctSIZE_T Bytes +** Number of bytes in the video memory heap. +** +** gctSIZE_T Threshold +** Minimum number of bytes beyond am allocation before the node is +** split. Can be used as a minimum alignment requirement. +** +** gctSIZE_T BankSize +** Number of bytes per physical memory bank. Used by bank +** optimization. +** +** OUTPUT: +** +** gckVIDMEM * Memory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object. +*/ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T BankSize, + OUT gckVIDMEM * Memory + ) +{ + gckVIDMEM memory = gcvNULL; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctINT i, banks = 0; + + gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu " + "BankSize=%lu", + Os, BaseAddress, Bytes, Threshold, BankSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Allocate the gckVIDMEM object. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(struct _gckVIDMEM), + (gctPOINTER *) &memory)); + + /* Initialize the gckVIDMEM object. */ + memory->object.type = gcvOBJ_VIDMEM; + memory->os = Os; + + /* Set video memory heap information. */ + memory->baseAddress = BaseAddress; + memory->bytes = Bytes; + memory->freeBytes = Bytes; + memory->threshold = Threshold; + memory->mutex = gcvNULL; + + BaseAddress = 0; + + /* Walk all possible banks. */ + for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i) + { + gctSIZE_T bytes; + + if (BankSize == 0) + { + /* Use all bytes for the first bank. */ + bytes = Bytes; + } + else + { + /* Compute number of bytes for this bank. */ + bytes = gcmALIGN(BaseAddress + 1, BankSize) - BaseAddress; + + if (bytes > Bytes) + { + /* Make sure we don't exceed the total number of bytes. */ + bytes = Bytes; + } + } + + if (bytes == 0) + { + /* Mark heap is not used. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = gcvNULL; + continue; + } + + /* Allocate one gcuVIDMEM_NODE union. */ + gcmkONERROR( + gckOS_Allocate(Os, + gcmSIZEOF(gcuVIDMEM_NODE), + (gctPOINTER *) &node)); + + /* Initialize gcuVIDMEM_NODE union. */ + node->VidMem.memory = memory; + + node->VidMem.next = + node->VidMem.prev = + node->VidMem.nextFree = + node->VidMem.prevFree = &memory->sentinel[i]; + + node->VidMem.offset = BaseAddress; + node->VidMem.bytes = bytes; + node->VidMem.alignment = 0; + node->VidMem.physical = 0; + node->VidMem.pool = gcvPOOL_UNKNOWN; + + node->VidMem.locked = 0; + +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = 0; +#endif + + /* Initialize the linked list of nodes. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = node; + + /* Mark sentinel. */ + memory->sentinel[i].VidMem.bytes = 0; + + /* Adjust address for next bank. */ + BaseAddress += bytes; + Bytes -= bytes; + banks ++; + } + + /* Assign all the bank mappings. */ + memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1; + memory->mapping[gcvSURF_BITMAP] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_DEPTH] = banks - 1; + memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TEXTURE] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_VERTEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_INDEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TILE_STATUS] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] INDEX: bank %d", + memory->mapping[gcvSURF_INDEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] VERTEX: bank %d", + memory->mapping[gcvSURF_VERTEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TEXTURE: bank %d", + memory->mapping[gcvSURF_TEXTURE]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] RENDER_TARGET: bank %d", + memory->mapping[gcvSURF_RENDER_TARGET]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] DEPTH: bank %d", + memory->mapping[gcvSURF_DEPTH]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TILE_STATUS: bank %d", + memory->mapping[gcvSURF_TILE_STATUS]); + + /* Allocate the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex)); + + /* Return pointer to the gckVIDMEM object. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (memory != gcvNULL) + { + if (memory->mutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex)); + } + + for (i = 0; i < banks; ++i) + { + /* Free the heap. */ + gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL); + gcmkVERIFY_OK(gckOS_Free(Os, memory->sentinel[i].VidMem.next)); + } + + /* Free the object. */ + gcmkVERIFY_OK(gckOS_Free(Os, memory)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Destroy +** +** Destroy an gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ) +{ + gcuVIDMEM_NODE_PTR node, next; + gctINT i; + + gcmkHEADER_ARG("Memory=0x%x", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = next) + { + /* Save pointer to the next node. */ + next = node->VidMem.next; + + /* Free the node. */ + gcmkVERIFY_OK(gckOS_Free(Memory->os, node)); + } + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex)); + + /* Mark the object as unknown. */ + Memory->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVIDMEM object. */ + gcmkVERIFY_OK(gckOS_Free(Memory->os, Memory)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Allocate +** +** Allocate rectangular memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctUINT Width +** Width of rectangle to allocate. Make sure the width is properly +** aligned. +** +** gctUINT Height +** Height of rectangle to allocate. Make sure the height is properly +** aligned. +** +** gctUINT Depth +** Depth of rectangle to allocate. This equals to the number of +** rectangles to allocate contiguously (i.e., for cubic maps and volume +** textures). +** +** gctUINT BytesPerPixel +** Number of bytes per pixel. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gctSIZE_T bytes; + gceSTATUS status; + + gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u " + "Alignment=%u Type=%d", + Memory, Width, Height, Depth, BytesPerPixel, Alignment, + Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Width > 0); + gcmkVERIFY_ARGUMENT(Height > 0); + gcmkVERIFY_ARGUMENT(Depth > 0); + gcmkVERIFY_ARGUMENT(BytesPerPixel > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Compute linear size. */ + bytes = Width * Height * Depth * BytesPerPixel; + + /* Allocate through linear function. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Handle, Node)); +#else + gcmkONERROR( + gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node)); +#endif + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gcuVIDMEM_NODE_PTR +_FindNode( + IN gckVIDMEM Memory, + IN gctINT Bank, + IN gctSIZE_T Bytes, + IN OUT gctUINT32_PTR Alignment + ) +{ + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + + /* Walk all free nodes until we have one that is big enough or we have + reached the sentinel. */ + for (node = Memory->sentinel[Bank].VidMem.nextFree; + node->VidMem.bytes != 0; + node = node->VidMem.nextFree) + { + /* Compute number of bytes to skip for alignment. */ + alignment = (*Alignment == 0) + ? 0 + : (*Alignment - (node->VidMem.offset % *Alignment)); + + if (alignment == *Alignment) + { + /* Node is already aligned. */ + alignment = 0; + } + + if (node->VidMem.bytes >= Bytes + alignment) + { + /* This node is big enough. */ + *Alignment = alignment; + return node; + } + } + + /* Not enough memory. */ + return gcvNULL; +} + +/******************************************************************************* +** +** gckVIDMEM_AllocateLinear +** +** Allocate linear memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, +#ifdef __QNXNTO__ + IN gctHANDLE Handle, +#endif + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + gctINT bank, i; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d", + Memory, Bytes, Alignment, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); +#ifdef __QNXNTO__ + gcmkVERIFY_ARGUMENT(Handle != gcvNULL); +#endif + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Bytes > Memory->freeBytes) + { + /* Not enough memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Find the default bank for this surface type. */ + gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping)); + bank = Memory->mapping[Type]; + alignment = Alignment; + + /* Find a free node in the default bank. */ + node = _FindNode(Memory, bank, Bytes, &alignment); + + /* Out of memory? */ + if (node == gcvNULL) + { + /* Walk all lower banks. */ + for (i = bank - 1; i >= 0; --i) + { + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, &alignment); + if (node != gcvNULL) + { + break; + } + } + } + + if (node == gcvNULL) + { + /* Walk all upper banks. */ + for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + if (Memory->sentinel[i].VidMem.nextFree == gcvNULL) + { + /* Abort when we reach unused banks. */ + break; + } + + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, &alignment); + if (node != gcvNULL) + { + break; + } + } + } + + if (node == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Do we have an alignment? */ + if (alignment > 0) + { + /* Split the node so it is aligned. */ + if (_Split(Memory->os, node, alignment)) + { + /* Successful split, move to aligned node. */ + node = node->VidMem.next; + + /* Remove alignment. */ + alignment = 0; + } + } + + /* Do we have enough memory after the allocation to split it? */ + if (node->VidMem.bytes - Bytes > Memory->threshold) + { + /* Adjust the node size. */ + _Split(Memory->os, node, Bytes); + } + + /* Remove the node from the free list. */ + node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree; + node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree; + node->VidMem.nextFree = + node->VidMem.prevFree = gcvNULL; + + /* Fill in the information. */ + node->VidMem.alignment = alignment; + node->VidMem.memory = Memory; +#ifdef __QNXNTO__ + node->VidMem.logical = gcvNULL; + node->VidMem.handle = Handle; +#endif + + /* Adjust the number of free bytes. */ + Memory->freeBytes -= node->VidMem.bytes; + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + + /* Return the pointer to the node. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Allocated %u bytes @ 0x%x [0x%08X]", + node->VidMem.bytes, node, node->VidMem.offset); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Free +** +** Free an allocated video memory node. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gckVIDMEM memory = gcvNULL; + gcuVIDMEM_NODE_PTR node; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked > 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM, + "Node 0x%x is locked (%d)", + Node, Node->VidMem.locked); + + /* Force unlock. */ + Node->VidMem.locked = 0; + } + + /* Extract pointer to gckVIDMEM object owning the node. */ + memory = Node->VidMem.memory; + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + +#ifdef __QNXNTO__ + /* Reset handle to 0. */ + Node->VidMem.logical = gcvNULL; + Node->VidMem.handle = 0; + + /* Don't try to a re-free an already freed node. */ + if ((Node->VidMem.nextFree == gcvNULL) + && (Node->VidMem.prevFree == gcvNULL) + ) +#endif + { + /* Update the number of free bytes. */ + memory->freeBytes += Node->VidMem.bytes; + + /* Find the next free node. */ + for (node = Node->VidMem.next; + node->VidMem.nextFree == gcvNULL; + node = node->VidMem.next) ; + + /* Insert this node in the free list. */ + Node->VidMem.nextFree = node; + Node->VidMem.prevFree = node->VidMem.prevFree; + + Node->VidMem.prevFree->VidMem.nextFree = + node->VidMem.prevFree = Node; + + /* Is the next node a free node and not the sentinel? */ + if ((Node->VidMem.next == Node->VidMem.nextFree) + && (Node->VidMem.next->VidMem.bytes != 0) + ) + { + /* Merge this node with the next node. */ + gcmkONERROR(_Merge(memory->os, node = Node)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + + /* Is the previous node a free node and not the sentinel? */ + if ((Node->VidMem.prev == Node->VidMem.prevFree) + && (Node->VidMem.prev->VidMem.bytes != 0) + ) + { + /* Merge this node with the previous node. */ + gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /*************************** Virtual Memory *******************************/ + + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + +#ifdef __QNXNTO__ + if (!Node->Virtual.unlockPending && (Node->Virtual.locked > 0)) +#else + if (!Node->Virtual.pending && (Node->Virtual.locked > 0)) +#endif + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM, + "gckVIDMEM_Free: Virtual node 0x%x is locked (%d)", + Node, Node->Virtual.locked); + + /* Force unlock. */ + Node->Virtual.locked = 0; + } + +#ifdef __QNXNTO__ + if (!Node->Virtual.freePending) { if (Node->Virtual.unlockPending) +#else + if (Node->Virtual.pending) +#endif + { + gcmkASSERT(Node->Virtual.locked == 1); + + /* Schedule the node to be freed. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "gckVIDMEM_Free: Scheduling node 0x%x to be freed later", + Node); + + /* Schedule the video memory to be freed again. */ + gcmkONERROR(gckEVENT_FreeVideoMemory(Node->Virtual.kernel->event, + Node, + gcvKERNEL_PIXEL)); + +#ifdef __QNXNTO__ + Node->Virtual.freePending = gcvTRUE; } +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_SKIP; + } + + else + { + /* Free the virtual memory. */ + gcmkVERIFY_OK(gckOS_FreePagedMemory(Node->Virtual.kernel->os, + Node->Virtual.physical, + Node->Virtual.bytes)); + + /* Destroy the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + + +#ifdef __QNXNTO__ +/******************************************************************************* +** +** gcoVIDMEM_FreeHandleMemory +** +** Free all allocated video memory nodes for a handle. +** +** INPUT: +** +** gcoVIDMEM Memory +** Pointer to an gcoVIDMEM object.. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_FreeHandleMemory( + IN gckVIDMEM Memory, + IN gctHANDLE Handle + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR node; + gctINT i; + gctUINT32 nodeCount = 0, byteCount = 0; + gctBOOL again; + + gcmkHEADER_ARG("Memory=0x%x Handle=0x%x", Memory, Handle); + + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap if it is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + do + { + again = gcvFALSE; + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = node->VidMem.next) + { + /* Free the node if it was allocated by Handle. */ + if (node->VidMem.handle == Handle) + { + /* Unlock video memory. */ + while (gckVIDMEM_Unlock(node, gcvSURF_TYPE_UNKNOWN, gcvNULL, gcvNULL) + != gcvSTATUS_MEMORY_UNLOCKED) + ; + + nodeCount++; + byteCount += node->VidMem.bytes; + + /* Free video memory. */ + gcmkVERIFY_OK(gckVIDMEM_Free(node, gcvNULL)); + + /* + * Freeing may cause a merge which will invalidate our iteration. + * Don't be clever, just restart. + */ + again = gcvTRUE; + + break; + } + } + } + while (again); + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** gckVIDMEM_Lock +** +** Lock a video memory node and return it's hardware specific address. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable that will hold the hardware specific address. +*/ +gceSTATUS +gckVIDMEM_Lock( + IN gcuVIDMEM_NODE_PTR Node, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctBOOL locked = gcvFALSE; + gckOS os = gcvNULL; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + /* Increment the lock count. */ + Node->VidMem.locked ++; + + /* Return the address of the node. */ + *Address = Node->VidMem.memory->baseAddress + + Node->VidMem.offset + + Node->VidMem.alignment; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Locked node 0x%x (%d) @ 0x%08X", + Node, + Node->VidMem.locked, + *Address); + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extract the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Increment the lock count. */ + if (Node->Virtual.locked ++ == 0) + { + /* Is this node pending for a final unlock? */ +#ifdef __QNXNTO__ + if (!Node->Virtual.contiguous && Node->Virtual.unlockPending) +#else + if (!Node->Virtual.contiguous && Node->Virtual.pending) +#endif + { + /* Make sure we have a page table. */ + gcmkASSERT(Node->Virtual.pageTable != gcvNULL); + + /* Remove pending unlock. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + } + + /* First lock - create a page table. */ + gcmkASSERT(Node->Virtual.pageTable == gcvNULL); + + /* Make sure we mark our node as not flushed. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + + /* Lock the allocated pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_LockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.userPID, + &Node->Virtual.logical, + &Node->Virtual.pageCount)); +#else + gcmkONERROR( + gckOS_LockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + &Node->Virtual.logical, + &Node->Virtual.pageCount)); +#endif + + locked = gcvTRUE; + + if (Node->Virtual.contiguous) + { + /* Get physical address directly */ + gcmkONERROR(gckOS_GetPhysicalAddress(os, + Node->Virtual.logical, + &Node->Virtual.address)); + } + else + { + /* Allocate pages inside the MMU. */ + gcmkONERROR( + gckMMU_AllocatePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageCount, + &Node->Virtual.pageTable, + &Node->Virtual.address)); + + /* Map the pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_MapPages(os, + Node->Virtual.physical, + Node->Virtual.logical, + Node->Virtual.pageCount, + Node->Virtual.pageTable)); +#else + gcmkONERROR( + gckOS_MapPages(os, + Node->Virtual.physical, + Node->Virtual.pageCount, + Node->Virtual.pageTable)); +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Mapped virtual node 0x%x to 0x%08X", + Node, + Node->Virtual.address); + } + } + + /* Return hardware address. */ + *Address = Node->Virtual.address; + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; + +OnError: + if (locked) + { + if (Node->Virtual.pageTable != gcvNULL) + { + /* Free the pages from the MMU. */ + gcmkVERIFY_OK( + gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + + Node->Virtual.pageTable = gcvNULL; + } + + /* Unlock the pages. */ +#ifdef __QNXNTO__ + gcmkVERIFY_OK( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.userPID, + Node->Virtual.bytes, + Node->Virtual.logical)); +#else + gcmkVERIFY_OK( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical)); +#endif + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Unlock +** +** Unlock a video memory node. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a locked gcuVIDMEM_NODE union. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +** +** gctSIZE_T * CommandSize +** Pointer to a variable specifying the number of bytes in the command +** buffer specified by 'Commands'. If gcvNULL, there is no command +** buffer and the video memory shoud be unlocked synchronously. +** +** gctBOOL * Asynchroneous +** Pointer to a variable specifying whether the surface should be +** unlocked asynchroneously or not. +** +** OUTPUT: +** +** gctBOOL * Asynchroneous +** Pointer to a variable receiving the number of bytes used in the +** command buffer specified by 'Commands'. If gcvNULL, there is no +** command buffer. +*/ +gceSTATUS +gckVIDMEM_Unlock( + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ) +{ + gceSTATUS status; + gckKERNEL kernel; + gckHARDWARE hardware; + gctPOINTER buffer; + gctSIZE_T requested, bufferSize; + gckCOMMAND command = gcvNULL; + gceKERNEL_FLUSH flush; + gckOS os = gcvNULL; + gctBOOL acquired = gcvFALSE; + gctBOOL needRelease = gcvFALSE; + gctBOOL pendingUnlock = gcvFALSE; + + gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d", + Node, Type, gcmOPT_VALUE(Asynchroneous)); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked <= 0) + { + /* The surface was not locked. */ + gcmkONERROR(gcvSTATUS_MEMORY_UNLOCKED); + } + + /* Decrement the lock count. */ + Node->VidMem.locked --; + + if (Asynchroneous != gcvNULL) + { + /* No need for any events. */ + *Asynchroneous = gcvFALSE; + } + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckKERNEL object pointer. */ + kernel = Node->Virtual.kernel; + gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL); + + /* Verify the gckHARDWARE object pointer. */ + hardware = Node->Virtual.kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Verify the gckCOMMAND object pointer. */ + command = Node->Virtual.kernel->command; + gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); + + if (Asynchroneous == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "gckVIDMEM_Unlock: Unlocking virtual node 0x%x (%d)", + Node, + Node->Virtual.locked); + + /* Get the gckOS object pointer. */ + os = kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + + /* If we need to unlock a node from virtual memory we have to be + ** very carefull. If the node is still inside the caches we + ** might get a bus error later if the cache line needs to be + ** replaced. So - we have to flush the caches before we do + ** anything. We also need to stall to make sure the flush has + ** happened. However - when we get to this point we are inside + ** the interrupt handler and we cannot just gckCOMMAND_Wait + ** because it will wait forever. So - what we do here is we + ** verify the type of the surface, flush the appropriate cache, + ** mark the node as flushed, and issue another unlock to unmap + ** the MMU. */ + if (!Node->Virtual.contiguous + && (Node->Virtual.locked == 1) +#ifdef __QNXTO__ + && !Node->Virtual.unlockPending +#else + && !Node->Virtual.pending +#endif + ) + { + if (Type == gcvSURF_BITMAP) + { + /* Flush 2D cache. */ + flush = gcvFLUSH_2D; + } + else if (Type == gcvSURF_RENDER_TARGET) + { + /* Flush color cache. */ + flush = gcvFLUSH_COLOR; + } + else if (Type == gcvSURF_DEPTH) + { + /* Flush depth cache. */ + flush = gcvFLUSH_DEPTH; + } + else + { + /* No flush required. */ + flush = (gceKERNEL_FLUSH) 0; + } + + gcmkONERROR( + gckHARDWARE_Flush(hardware, flush, gcvNULL, &requested)); + + if (requested != 0) + { + gcmkONERROR( + gckCOMMAND_Reserve(command, + requested, + &buffer, + &bufferSize)); + + needRelease = gcvTRUE; + + gcmkONERROR(gckHARDWARE_Flush(hardware, + flush, + buffer, + &bufferSize)); + + gcmkONERROR( + gckEVENT_Unlock(Node->Virtual.kernel->event, + gcvKERNEL_PIXEL, + Node, + Type)); + + /* Mark node as pending. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPending = gcvTRUE; +#else + Node->Virtual.pending = gcvTRUE; +#endif + + needRelease = gcvFALSE; + + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + pendingUnlock = gcvTRUE; + } + } + + if (!pendingUnlock) + { + if (Node->Virtual.locked == 0) + { + status = gcvSTATUS_MEMORY_UNLOCKED; + goto OnError; + } + + /* Decrement lock count. */ + -- Node->Virtual.locked; + + /* See if we can unlock the resources. */ + if (Node->Virtual.locked == 0) + { + /* Unlock the pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.userPID, + Node->Virtual.bytes, + Node->Virtual.logical)); +#else + gcmkONERROR( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical)); +#endif + + /* Free the page table. */ + if (Node->Virtual.pageTable != gcvNULL) + { + gcmkONERROR( + gckMMU_FreePages(Node->Virtual.kernel->mmu, + Node->Virtual.pageTable, + Node->Virtual.pageCount)); + + /* Mark page table as freed. */ + Node->Virtual.pageTable = gcvNULL; + } + + /* Mark node as unlocked. */ +#ifdef __QNXTO + Node->Virtual.unlockPending = gcvFALSE; +#else + Node->Virtual.pending = gcvFALSE; +#endif + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Unmapped virtual node 0x%x from 0x%08X", + Node, Node->Virtual.address); + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Scheduled unlock for virtual node 0x%x", + Node); + + /* Schedule the surface to be unlocked. */ + *Asynchroneous = gcvTRUE; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous)); + return gcvSTATUS_OK; + +OnError: + if (needRelease) + { + gcmkVERIFY_OK(gckCOMMAND_Release(command)); + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#ifdef __QNXNTO__ +/* Set the allocating process' PID for this node. */ +gceSTATUS +gckVIDMEM_SetPID( + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT32 Pid + ) +{ + if (Node != gcvNULL) + { + if (Node->VidMem.memory->object.type != gcvOBJ_VIDMEM) + { + Node->Virtual.userPID = Pid; + } + + } + else + { + return gcvSTATUS_INVALID_OBJECT; + } + + return gcvSTATUS_OK; +} +#endif + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_debug.c b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_debug.c new file mode 100644 index 0000000..ad9eef9 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_debug.c @@ -0,0 +1,449 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" +#include "linux/spinlock.h" +#include <stdarg.h> + +/* + gcdBUFFERED_OUTPUT + + When set to non-zero, all output is collected into a buffer with the + specified size. Once the buffer gets full, or the token "$$FLUSH$$" has + been received, the debug buffer will be printed to the console. +*/ +#define gcdBUFFERED_OUTPUT 0 + +/******************************************************************************\ +******************************** Debug Variables ******************************* +\******************************************************************************/ + +static gceSTATUS _lastError = gcvSTATUS_OK; +static gctUINT32 _debugLevel = gcvLEVEL_ERROR; +static gctUINT32 _debugZones = gcvZONE_NONE; +static gctINT _indent = 0; +static spinlock_t _lock = __SPIN_LOCK_UNLOCKED(); + +static void +OutputDebugString( + IN gctCONST_STRING String + ) +{ +#if gcdBUFFERED_OUTPUT + static gctCHAR outputBuffer[gcdBUFFERED_OUTPUT]; + static gctINT outputBufferIndex = 0; + gctINT n, i; + + n = (String != gcvNULL) ? strlen(String) + 1 : 0; + + if ((n == 0) || (outputBufferIndex + n > gcmSIZEOF(outputBuffer))) + { + for (i = 0; i < outputBufferIndex; i += strlen(outputBuffer + i) + 1) + { + printk(outputBuffer + i); + } + + outputBufferIndex = 0; + } + + if (n > 0) + { + memcpy(outputBuffer + outputBufferIndex, String, n); + outputBufferIndex += n; + } +#else + if (String != gcvNULL) + { + printk(String); + } +#endif +} + +static void +_Print( + IN gctCONST_STRING Message, + IN va_list Arguments + ) +{ + char buffer[1024]; + int i, n; + + if (strcmp(Message, "$$FLUSH$$") == 0) + { + spin_lock(&_lock); + { + OutputDebugString(gcvNULL); + } + spin_unlock(&_lock); + return; + } + + if (strncmp(Message, "--", 2) == 0) + { + if (_indent == 0) + { + printk("ERROR: _indent=0\n"); + } + + _indent -= 2; + } + + for (i = 0; i < _indent; ++i) + { + buffer[i] = ' '; + } + + /* Print message to buffer. */ + n = vsnprintf(buffer + i, sizeof(buffer) - i, Message, Arguments); + if ((n <= 0) || (buffer[i + n - 1] != '\n')) + { + /* Append new-line. */ + strncat(buffer, "\n", sizeof(buffer)); + } + + /* Output to debugger. */ + spin_lock(&_lock); + { + OutputDebugString(buffer); + } + spin_unlock(&_lock); + + if (strncmp(Message, "++", 2) == 0) + { + _indent += 2; + } +} + +/******************************************************************************\ +********************************* Debug Macros ********************************* +\******************************************************************************/ + +#define _DEBUGPRINT(Message) \ +{ \ + va_list arguments; \ + \ + va_start(arguments, Message); \ + _Print(Message, arguments); \ + va_end(arguments); \ +} + +/******************************************************************************\ +********************************** Debug Code ********************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Print +** +** Send a message to the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTrace +** +** Send a leveled message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level of message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) +{ + if (Level > _debugLevel) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceZone +** +** Send a leveled and zoned message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level for message. +** +** gctUINT32 Zone +** Debug zone for message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) +{ + if ((Level > _debugLevel) || !(Zone & _debugZones)) + { + return; + } + + _DEBUGPRINT(Message); +} + +/******************************************************************************* +** +** gckOS_DebugBreak +** +** Break into the debugger. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugBreak( + void + ) +{ + gckOS_DebugTrace(gcvLEVEL_ERROR, "gckOS_DebugBreak"); +} + +/******************************************************************************* +** +** gckOS_DebugFatal +** +** Send a message to the debugger and break into the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ) +{ + _DEBUGPRINT(Message); + + /* Break into the debugger. */ + gckOS_DebugBreak(); +} + +/******************************************************************************* +** +** gckOS_SetDebugLevel +** +** Set the debug level. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ) +{ + _debugLevel = Level; +} + +/******************************************************************************* +** +** gckOS_SetDebugZone +** +** Set the debug zone. +** +** INPUT: +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ) +{ + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugLevelZone +** +** Set the debug level and zone. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ) +{ + _debugLevel = Level; + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugZones +** +** Enable or disable debug zones. +** +** INPUT: +** +** gctUINT32 Zones +** Debug zones to enable or disable. +** +** gctBOOL Enable +** Set to gcvTRUE to enable the zones (or the Zones with the current +** zones) or gcvFALSE to disable the specified Zones. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ) +{ + if (Enable) + { + /* Enable the zones. */ + _debugZones |= Zones; + } + else + { + /* Disable the zones. */ + _debugZones &= ~Zones; + } +} + +/******************************************************************************* +** +** gckOS_Verify +** +** Called to verify the result of a function call. +** +** INPUT: +** +** gceSTATUS Status +** Function call result. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Verify( + IN gceSTATUS Status + ) +{ + _lastError = Status; +} + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.c b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.c new file mode 100644 index 0000000..8cba84e --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.c @@ -0,0 +1,843 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" +#include <linux/pagemap.h> +#include <linux/seq_file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/slab.h> + +#define _GC_OBJ_ZONE gcvZONE_DEVICE + +#ifdef FLAREON +static struct dove_gpio_irq_handler gc500_handle; +#endif + +/******************************************************************************\ +******************************** gckGALDEVICE Code ******************************* +\******************************************************************************/ + +gceSTATUS +gckGALDEVICE_AllocateMemory( + IN gckGALDEVICE Device, + IN gctSIZE_T Bytes, + OUT gctPOINTER *Logical, + OUT gctPHYS_ADDR *Physical, + OUT gctUINT32 *PhysAddr + ) +{ + gceSTATUS status; + + gcmkVERIFY_ARGUMENT(Device != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PhysAddr != NULL); + + status = gckOS_AllocateContiguous(Device->os, + gcvFALSE, + &Bytes, + Physical, + Logical); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: error status->0x%x", + status); + + return status; + } + + *PhysAddr = ((PLINUX_MDL)*Physical)->dmaHandle - Device->baseAddress; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "gckGALDEVICE_AllocateMemory: phys_addr->0x%x phsical->0x%x Logical->0x%x", + (gctUINT32)*Physical, + (gctUINT32)*PhysAddr, + (gctUINT32)*Logical); + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckGALDEVICE_FreeMemory( + IN gckGALDEVICE Device, + IN gctPOINTER Logical, + IN gctPHYS_ADDR Physical) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + return gckOS_FreeContiguous(Device->os, + Physical, + Logical, + ((PLINUX_MDL)Physical)->numPages*PAGE_SIZE); +} + +irqreturn_t isrRoutine(int irq, void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + int handled = 0; + + /* Call kernel interrupt notification. */ + if (gckKERNEL_Notify(device->kernel, + gcvNOTIFY_INTERRUPT, + gcvTRUE) == gcvSTATUS_OK) + { + device->dataReady = gcvTRUE; + + up(&device->sema); + + handled = 1; + } + + return IRQ_RETVAL(handled); +} + +int threadRoutine(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting isr Thread with extension->%p", + device); + + for (;;) + { + static int down; + + down = down_interruptible(&device->sema); + device->dataReady = gcvFALSE; + + if (device->killThread == gcvTRUE) + { + /* The daemon exits. */ + while (!kthread_should_stop()) + { + gckOS_Delay(device->os, 1); + } + + return 0; + } + else + { + gckKERNEL_Notify(device->kernel, gcvNOTIFY_INTERRUPT, gcvFALSE); + } + } +} + +/******************************************************************************* +** +** gckGALDEVICE_Setup_ISR +** +** Start the ISR routine. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Setup successfully. +** gcvSTATUS_GENERIC_IO +** Setup failed. +*/ +gceSTATUS +gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ) +{ + gctINT ret; + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->irqLine < 0) + { + return gcvSTATUS_GENERIC_IO; + } + + /* Hook up the isr based on the irq line. */ +#ifdef FLAREON + gc500_handle.dev_name = "galcore interrupt service"; + gc500_handle.dev_id = Device; + gc500_handle.handler = isrRoutine; + gc500_handle.intr_gen = GPIO_INTR_LEVEL_TRIGGER; + gc500_handle.intr_trig = GPIO_TRIG_HIGH_LEVEL; + ret = dove_gpio_request (DOVE_GPIO0_7, &gc500_handle); +#else + ret = request_irq(Device->irqLine, + isrRoutine, + IRQF_DISABLED, + "galcore interrupt service", + Device); +#endif + + + if (ret != 0) { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Setup_ISR: " + "Could not register irq line->%d", + Device->irqLine); + + Device->isrInitialized = gcvFALSE; + + return gcvSTATUS_GENERIC_IO; + } + + Device->isrInitialized = gcvTRUE; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Setup_ISR: " + "Setup the irq line->%d", + Device->irqLine); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Release_ISR +** +** Release the irq line. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* release the irq */ + if (Device->isrInitialized) + { +#ifdef FLAREON + dove_gpio_free (DOVE_GPIO0_7, "galcore interrupt service"); +#else + free_irq(Device->irqLine, Device); +#endif + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start_Thread +** +** Start the daemon thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +** gcvSTATUS_GENERIC_IO +** Start failed. +*/ +gceSTATUS +gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* start the kernel thread */ + Device->threadCtxt = kthread_run(threadRoutine, + Device, + "galcore daemon thread"); + + Device->threadInitialized = gcvTRUE; + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Start_Thread: " + "Start the daemon thread."); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop_Thread +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* stop the thread */ + if (Device->threadInitialized) + { + Device->killThread = gcvTRUE; + up(&Device->sema); + + kthread_stop(Device->threadCtxt); + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start +** +** Start the gal device, including the following actions: setup the isr routine +** and start the daemoni thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +*/ +gceSTATUS +gckGALDEVICE_Start( + IN gckGALDEVICE Device + ) +{ + /* start the daemon thread */ + gcmkVERIFY_OK(gckGALDEVICE_Start_Thread(Device)); + + /* setup the isr routine */ + gcmkVERIFY_OK(gckGALDEVICE_Setup_ISR(Device)); + + /* Switch to SUSPEND power state. */ + gcmkVERIFY_OK( + gckHARDWARE_SetPowerManagementState(Device->kernel->hardware, + gcvPOWER_SUSPEND_ATPOWERON)); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop( + gckGALDEVICE Device + ) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* Switch to ON power state. */ + gcmkVERIFY_OK( + gckHARDWARE_SetPowerManagementState(Device->kernel->hardware, + gcvPOWER_ON)); + + if (Device->isrInitialized) + { + gckGALDEVICE_Release_ISR(Device); + } + + if (Device->threadInitialized) + { + gckGALDEVICE_Stop_Thread(Device); + } + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Construct +** +** Constructor. +** +** INPUT: +** +** OUTPUT: +** +** gckGALDEVICE * Device +** Pointer to a variable receiving the gckGALDEVICE object pointer on +** success. +*/ +gceSTATUS +gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ) +{ + gctUINT32 internalBaseAddress = 0, internalAlignment = 0; + gctUINT32 externalBaseAddress = 0, externalAlignment = 0; + gctUINT32 horizontalTileSize, verticalTileSize; + gctUINT32 physAddr; + gctUINT32 physical; + gckGALDEVICE device; + gceSTATUS status; + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Enter gckGALDEVICE_Construct"); + + /* Allocate device structure. */ + device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL); + if (!device) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Can't allocate memory."); + + return gcvSTATUS_OUT_OF_MEMORY; + } + memset(device, 0, sizeof(struct _gckGALDEVICE)); + + physical = RegisterMemBase; + + /* Set up register memory region */ + if (physical != 0) + { + /* Request a region. */ + request_mem_region(RegisterMemBase, RegisterMemSize, "galcore register region"); + device->registerBase = (gctPOINTER) ioremap_nocache(RegisterMemBase, + RegisterMemSize); + if (!device->registerBase) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Unable to map location->0x%lX for size->%ld", + RegisterMemBase, + RegisterMemSize); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + physical += RegisterMemSize; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "RegisterBase after mapping Address->0x%x is 0x%x", + (gctUINT32)RegisterMemBase, + (gctUINT32)device->registerBase); + } + + /* construct the gckOS object */ + device->baseAddress = BaseAddress; + gcmkVERIFY_OK(gckOS_Construct(device, &device->os)); + + /* construct the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Construct(device->os, device, &device->kernel)); + + /* Setup the Isr manager. */ + gcmkVERIFY_OK(gckHARDWARE_SetIsrManager(device->kernel->hardware, + (gctISRMANAGERFUNC)gckGALDEVICE_Setup_ISR, + (gctISRMANAGERFUNC)gckGALDEVICE_Release_ISR, + device)); + + gcmkVERIFY_OK(gckHARDWARE_SetFastClear(device->kernel->hardware, + FastClear, + Compression)); + + /* query the ceiling of the system memory */ + gcmkVERIFY_OK(gckHARDWARE_QuerySystemMemory(device->kernel->hardware, + &device->systemMemorySize, + &device->systemMemoryBaseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: " + "Will be trying to allocate contiguous memory of 0x%x bytes", + (gctUINT32)device->systemMemoryBaseAddress); + +#if COMMAND_PROCESSOR_VERSION == 1 + /* start the command queue */ + gcmkVERIFY_OK(gckCOMMAND_Start(device->kernel->command)); +#endif + + /* initialize the thread daemon */ + sema_init(&device->sema, 0); + + device->threadInitialized = gcvFALSE; + device->killThread = gcvFALSE; + + /* initialize the isr */ + device->isrInitialized = gcvFALSE; + device->dataReady = gcvFALSE; + device->irqLine = IrqLine; + + device->signal = Signal; + + /* query the amount of video memory */ + gcmkVERIFY_OK(gckHARDWARE_QueryMemory(device->kernel->hardware, + &device->internalSize, + &internalBaseAddress, + &internalAlignment, + &device->externalSize, + &externalBaseAddress, + &externalAlignment, + &horizontalTileSize, + &verticalTileSize)); + + /* set up the internal memory region */ + if (device->internalSize > 0) + { + gceSTATUS status = gckVIDMEM_Construct(device->os, + internalBaseAddress, + device->internalSize, + internalAlignment, + 0, + &device->internalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->internalSize = 0; + } + else + { + /* map internal memory */ + device->internalPhysical = (gctPHYS_ADDR)physical; + device->internalLogical = (gctPOINTER)ioremap_nocache( + physical, device->internalSize); + + gcmkASSERT(device->internalLogical != NULL); + + physical += device->internalSize; + } + } + + if (device->externalSize > 0) + { + /* create the external memory heap */ + gceSTATUS status = gckVIDMEM_Construct(device->os, + externalBaseAddress, + device->externalSize, + externalAlignment, + 0, + &device->externalVidMem); + + if (gcmIS_ERROR(status)) + { + /* error, remove internal heap */ + device->externalSize = 0; + } + else + { + /* map internal memory */ + device->externalPhysical = (gctPHYS_ADDR)physical; + device->externalLogical = (gctPOINTER)ioremap_nocache( + physical, device->externalSize); + + gcmkASSERT(device->externalLogical != NULL); + + physical += device->externalSize; + } + } + + /* set up the contiguous memory */ + device->contiguousSize = ContiguousSize; + + if (ContiguousBase == 0) + { + status = gcvSTATUS_OUT_OF_MEMORY; + + while (device->contiguousSize > 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Will be trying to allocate contiguous memory of %ld bytes", + device->contiguousSize + ); + + /* allocate contiguous memory */ + status = gckGALDEVICE_AllocateMemory( + device, + device->contiguousSize, + &device->contiguousBase, + &device->contiguousPhysical, + &physAddr + ); + + if (gcmIS_SUCCESS(status)) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Contiguous allocated size->0x%08X Virt->0x%08lX physAddr->0x%08X", + device->contiguousSize, + device->contiguousBase, + physAddr + ); + + status = gckVIDMEM_Construct( + device->os, + physAddr | device->systemMemoryBaseAddress, + device->contiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_SUCCESS(status)) + { + device->contiguousMapped = gcvFALSE; + + /* success, abort loop */ + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "Using %u bytes of contiguous memory.", + device->contiguousSize + ); + + break; + } + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory( + device, + device->contiguousBase, + device->contiguousPhysical + )); + + device->contiguousBase = NULL; + } + + if (device->contiguousSize <= (4 << 20)) + { + device->contiguousSize = 0; + } + else + { + device->contiguousSize -= (4 << 20); + } + } + } + else + { + /* Create the contiguous memory heap. */ + status = gckVIDMEM_Construct( + device->os, + (ContiguousBase - device->baseAddress) | device->systemMemoryBaseAddress, + ContiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, roll back. */ + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + } + else + { + /* Map the contiguous memory. */ + request_mem_region( + ContiguousBase, + ContiguousSize, + "galcore managed memory" + ); + + device->contiguousPhysical = (gctPHYS_ADDR) ContiguousBase; + device->contiguousSize = ContiguousSize; + device->contiguousBase = (gctPOINTER) ioremap_nocache(ContiguousBase, ContiguousSize); + device->contiguousMapped = gcvTRUE; + + if (device->contiguousBase == gcvNULL) + { + /* Error, roll back. */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(device->contiguousVidMem)); + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + + status = gcvSTATUS_OUT_OF_RESOURCES; + } + } + } + + *Device = device; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Construct: Initialized device->%p contiguous->%lu @ %p (0x%08X)", + device, + device->contiguousSize, + device->contiguousBase, + device->contiguousPhysical); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Destroy +** +** Class destructor. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Destroy( + gckGALDEVICE Device) +{ + gcmkVERIFY_ARGUMENT(Device != NULL); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[ENTER] gckGALDEVICE_Destroy"); + + /* Destroy the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Destroy(Device->kernel)); + + if (Device->internalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem)); + + /* unmap the internal memory */ + iounmap(Device->internalLogical); + } + + if (Device->externalVidMem != gcvNULL) + { + /* destroy the internal heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem)); + + /* unmap the external memory */ + iounmap(Device->externalLogical); + } + + if (Device->contiguousVidMem != gcvNULL) + { + /* Destroy the contiguous heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem)); + + if (Device->contiguousMapped) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Unmapping contiguous memory->0x%08lX", + Device->contiguousBase); + + iounmap(Device->contiguousBase); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] gckGALDEVICE_Destroy: " + "Freeing contiguous memory->0x%08lX", + Device->contiguousBase); + + gcmkVERIFY_OK(gckGALDEVICE_FreeMemory(Device, + Device->contiguousBase, + Device->contiguousPhysical)); + } + } + + if (Device->registerBase) + { + iounmap(Device->registerBase); + } + + /* Destroy the gckOS object. */ + gcmkVERIFY_OK(gckOS_Destroy(Device->os)); + + kfree(Device); + + gcmkTRACE(gcvLEVEL_VERBOSE, "[galcore] Leave gckGALDEVICE_Destroy"); + + return gcvSTATUS_OK; +} + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.h b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.h new file mode 100644 index 0000000..ef5ee65 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_device.h @@ -0,0 +1,190 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_device_h_ +#define __gc_hal_kernel_device_h_ + +#define gcdkUSE_MEMORY_RECORD 1 + +#ifndef gcdkREPORT_VIDMEM_USAGE +#define gcdkREPORT_VIDMEM_USAGE 0 +#endif + +#ifdef ANDROID +#define gcdkREPORT_VIDMEM_LEAK 0 +#else +#define gcdkREPORT_VIDMEM_LEAK 1 +#endif + +/******************************************************************************\ +******************************* gckGALDEVICE Structure ******************************* +\******************************************************************************/ + +typedef struct _gckGALDEVICE +{ + /* Objects. */ + gckOS os; + gckKERNEL kernel; + + /* Attributes. */ + gctSIZE_T internalSize; + gctPHYS_ADDR internalPhysical; + gctPOINTER internalLogical; + gckVIDMEM internalVidMem; + gctSIZE_T externalSize; + gctPHYS_ADDR externalPhysical; + gctPOINTER externalLogical; + gckVIDMEM externalVidMem; + gckVIDMEM contiguousVidMem; + gctPOINTER contiguousBase; + gctPHYS_ADDR contiguousPhysical; + gctSIZE_T contiguousSize; + gctBOOL contiguousMapped; + gctPOINTER contiguousMappedUser; + gctSIZE_T systemMemorySize; + gctUINT32 systemMemoryBaseAddress; + gctPOINTER registerBase; + gctSIZE_T registerSize; + gctUINT32 baseAddress; + + /* IRQ management. */ + gctINT irqLine; + gctBOOL isrInitialized; + gctBOOL dataReady; + + /* Thread management. */ + struct task_struct *threadCtxt; + struct semaphore sema; + gctBOOL threadInitialized; + gctBOOL killThread; + + /* Signal management. */ + gctINT signal; + + /* Clock management. */ + struct clk *clk; +} +* gckGALDEVICE; + +#if gcdkUSE_MEMORY_RECORD +typedef enum _gceMEMORY_TYPE +{ + gcvNON_PAGED_MEMORY = 0, + gcvCONTIGUOUS_MEMORY, + gcvVIDEO_MEMORY +} +gceMEMORY_TYPE; + +typedef struct MEMORY_RECORD +{ + gceMEMORY_TYPE type; + + union + { + struct + { + gctSIZE_T bytes; + gctPHYS_ADDR physical; + gctPOINTER logical; + } + Memory; + + struct + { + gcuVIDMEM_NODE_PTR node; + gceSURF_TYPE type; + gctSIZE_T bytes; + } + VideoMemory; + } + u; + + struct MEMORY_RECORD * prev; + struct MEMORY_RECORD * next; +} +MEMORY_RECORD, * MEMORY_RECORD_PTR; +#endif + +typedef struct _gcsHAL_PRIVATE_DATA +{ + gckGALDEVICE device; + gctPOINTER mappedMemory; + gctPOINTER contiguousLogical; + +#if gcdkUSE_MEMORY_RECORD + MEMORY_RECORD memoryRecordList; + +#if gcdkREPORT_VIDMEM_USAGE + gctUINT64 allocatedMem[gcvSURF_NUM_TYPES]; + gctUINT64 maxAllocatedMem[gcvSURF_NUM_TYPES]; + gctUINT64 totalAllocatedMem; + gctUINT64 maxTotalAllocatedMem; +#endif +#endif +} +gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR; + +gceSTATUS gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start_Thread( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop_Thread( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 BaseAddress, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ); + +gceSTATUS gckGALDEVICE_Destroy( + IN gckGALDEVICE Device + ); + +#endif /* __gc_hal_kernel_device_h_ */ + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_driver.c b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_driver.c new file mode 100644 index 0000000..f5d25c7 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_driver.c @@ -0,0 +1,820 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include <linux/device.h> +#include <linux/slab.h> + +#include "gc_hal_kernel_linux.h" +#include "gc_hal_driver.h" +#include "gc_hal_user_context.h" + +#if USE_PLATFORM_DRIVER +#include <linux/platform_device.h> +#endif + +MODULE_DESCRIPTION("Vivante Graphics Driver"); +MODULE_LICENSE("GPL"); + +struct class *gpuClass; + +static gckGALDEVICE galDevice; + +static int major = 199; +module_param(major, int, 0644); + +int irqLine = -1; +module_param(irqLine, int, 0644); + +long registerMemBase = 0x80000000; +module_param(registerMemBase, long, 0644); + +ulong registerMemSize = 256 << 10; +module_param(registerMemSize, ulong, 0644); + +long contiguousSize = 4 << 20; +module_param(contiguousSize, long, 0644); + +ulong contiguousBase = 0; +module_param(contiguousBase, ulong, 0644); + +long bankSize = 32 << 20; +module_param(bankSize, long, 0644); + +int fastClear = -1; +module_param(fastClear, int, 0644); + +int compression = -1; +module_param(compression, int, 0644); + +int signal = 48; +module_param(signal, int, 0644); + +ulong baseAddress = 0; +module_param(baseAddress, ulong, 0644); + +int showArgs = 1; +module_param(showArgs, int, 0644); + +static int drv_open(struct inode *inode, struct file *filp); +static int drv_release(struct inode *inode, struct file *filp); +static long drv_ioctl(struct file *filp, unsigned int ioctlCode, + unsigned long arg); +static int drv_mmap(struct file * filp, struct vm_area_struct * vma); + +struct file_operations driver_fops = +{ + .open = drv_open, + .release = drv_release, + .unlocked_ioctl = drv_ioctl, + .mmap = drv_mmap, +}; + +int drv_open(struct inode *inode, struct file* filp) +{ + gcsHAL_PRIVATE_DATA_PTR private; + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "Entering drv_open\n"); + + private = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL); + + if (private == gcvNULL) + { + return -ENOTTY; + } + + /* Zero the memory. */ + gckOS_ZeroMemory(private, gcmSIZEOF(gcsHAL_PRIVATE_DATA)); + + private->device = galDevice; + private->mappedMemory = gcvNULL; + private->contiguousLogical = gcvNULL; + +#if gcdkUSE_MEMORY_RECORD + private->memoryRecordList.prev = &private->memoryRecordList; + private->memoryRecordList.next = &private->memoryRecordList; +#endif + + /* A process gets attached. */ + gcmkVERIFY_OK( + gckKERNEL_AttachProcess(galDevice->kernel, gcvTRUE)); + + if (galDevice->contiguousSize != 0 + && !galDevice->contiguousMapped) + { + gcmkVERIFY_OK(gckOS_MapMemory(galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + &private->contiguousLogical)); + } + + filp->private_data = private; + + return 0; +} + +extern void +OnProcessExit( + IN gckOS Os, + IN gckKERNEL Kernel + ); + +int drv_release(struct inode* inode, struct file* filp) +{ + gcsHAL_PRIVATE_DATA_PTR private; + gckGALDEVICE device; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Entering drv_close\n"); + + private = filp->private_data; + gcmkASSERT(private != gcvNULL); + + device = private->device; + +#ifndef ANDROID + gcmkVERIFY_OK(gckCOMMAND_Stall(device->kernel->command)); +#endif + + gcmkVERIFY_OK( + gckOS_DestroyAllUserSignals(galDevice->os)); + +#if gcdkUSE_MEMORY_RECORD + FreeAllMemoryRecord(galDevice->os, private, &private->memoryRecordList); + +#ifndef ANDROID + gcmkVERIFY_OK(gckCOMMAND_Stall(device->kernel->command)); +#endif +#endif + + if (!device->contiguousMapped) + { + if (private->contiguousLogical != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapMemory(galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + private->contiguousLogical)); + } + } + + /* A process gets detached. */ + gcmkVERIFY_OK( + gckKERNEL_AttachProcess(galDevice->kernel, gcvFALSE)); + + kfree(private); + filp->private_data = NULL; + + return 0; +} + +static long +drv_ioctl(struct file *filp, unsigned int ioctlCode, unsigned long arg) +{ + gcsHAL_INTERFACE iface; + gctUINT32 copyLen; + DRIVER_ARGS drvArgs; + gckGALDEVICE device; + gceSTATUS status; + gcsHAL_PRIVATE_DATA_PTR private; + + private = filp->private_data; + + if (private == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] drv_ioctl: private_data is NULL\n"); + + return -ENOTTY; + } + + device = private->device; + + if (device == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] drv_ioctl: device is NULL\n"); + + return -ENOTTY; + } + + if (ioctlCode != IOCTL_GCHAL_INTERFACE + && ioctlCode != IOCTL_GCHAL_KERNEL_INTERFACE) + { + /* Unknown command. Fail the I/O. */ + return -ENOTTY; + } + + /* Get the drvArgs to begin with. */ + copyLen = copy_from_user(&drvArgs, + (void *) arg, + sizeof(DRIVER_ARGS)); + + if (copyLen != 0) + { + /* The input buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + + /* Now bring in the gcsHAL_INTERFACE structure. */ + if ((drvArgs.InputBufferSize != sizeof(gcsHAL_INTERFACE)) + || (drvArgs.OutputBufferSize != sizeof(gcsHAL_INTERFACE)) + ) + { + return -ENOTTY; + } + + copyLen = copy_from_user(&iface, + drvArgs.InputBuffer, + sizeof(gcsHAL_INTERFACE)); + + if (copyLen != 0) + { + /* The input buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + +#if gcdkUSE_MEMORY_RECORD + if (iface.command == gcvHAL_EVENT_COMMIT) + { + MEMORY_RECORD_PTR mr; + gcsQUEUE_PTR queue = iface.u.Event.queue; + + while (queue != gcvNULL) + { + gcsQUEUE_PTR record, next; + + /* Map record into kernel memory. */ + gcmkERR_BREAK(gckOS_MapUserPointer(device->os, + queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) &record)); + + switch (record->iface.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + mr = FindMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvNON_PAGED_MEMORY, + record->iface.u.FreeNonPagedMemory.bytes, + record->iface.u.FreeNonPagedMemory.physical, + record->iface.u.FreeNonPagedMemory.logical); + + if (mr != gcvNULL) + { + DestroyMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid non-paged memory for free"); + } + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + mr = FindMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvCONTIGUOUS_MEMORY, + record->iface.u.FreeContiguousMemory.bytes, + record->iface.u.FreeContiguousMemory.physical, + record->iface.u.FreeContiguousMemory.logical); + + if (mr != gcvNULL) + { + DestroyMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid contiguous memory for free"); + } + break; + + case gcvHAL_FREE_VIDEO_MEMORY: + mr = FindVideoMemoryRecord(device->os, + private, + &private->memoryRecordList, + record->iface.u.FreeVideoMemory.node); + + if (mr != gcvNULL) + { + DestroyVideoMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid video memory for free"); + } + break; + + default: + break; + } + + /* Next record in the queue. */ + next = record->next; + + /* Unmap record from kernel memory. */ + gcmkERR_BREAK(gckOS_UnmapUserPointer(device->os, + queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + queue = next; + } + } +#endif + + status = gckKERNEL_Dispatch(device->kernel, + (ioctlCode == IOCTL_GCHAL_INTERFACE) , &iface); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] gckKERNEL_Dispatch returned %d.\n", + status); + } + + else if (gcmIS_ERROR(iface.status)) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DRIVER, + "[galcore] IOCTL %d returned %d.\n", + iface.command, + iface.status); + } + + /* See if this was a LOCK_VIDEO_MEMORY command. */ + else if (iface.command == gcvHAL_LOCK_VIDEO_MEMORY) + { + /* Special case for mapped memory. */ + if (private->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 *) private->mappedMemory + offset; + } + } +#if gcdkUSE_MEMORY_RECORD + else if (iface.command == gcvHAL_ALLOCATE_NON_PAGED_MEMORY) + { + CreateMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvNON_PAGED_MEMORY, + iface.u.AllocateNonPagedMemory.bytes, + iface.u.AllocateNonPagedMemory.physical, + iface.u.AllocateNonPagedMemory.logical); + } + else if (iface.command == gcvHAL_FREE_NON_PAGED_MEMORY) + { + MEMORY_RECORD_PTR mr; + + mr = FindMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvNON_PAGED_MEMORY, + iface.u.FreeNonPagedMemory.bytes, + iface.u.FreeNonPagedMemory.physical, + iface.u.FreeNonPagedMemory.logical); + + if (mr != gcvNULL) + { + DestroyMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid non-paged memory for free"); + } + } + else if (iface.command == gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY) + { + CreateMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvCONTIGUOUS_MEMORY, + iface.u.AllocateContiguousMemory.bytes, + iface.u.AllocateContiguousMemory.physical, + iface.u.AllocateContiguousMemory.logical); + } + else if (iface.command == gcvHAL_FREE_CONTIGUOUS_MEMORY) + { + MEMORY_RECORD_PTR mr; + + mr = FindMemoryRecord(device->os, + private, + &private->memoryRecordList, + gcvCONTIGUOUS_MEMORY, + iface.u.FreeContiguousMemory.bytes, + iface.u.FreeContiguousMemory.physical, + iface.u.FreeContiguousMemory.logical); + + if (mr != gcvNULL) + { + DestroyMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid contiguous memory for free"); + } + } + else if (iface.command == gcvHAL_ALLOCATE_VIDEO_MEMORY) + { + gctSIZE_T bytes = (iface.u.AllocateVideoMemory.node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + ? iface.u.AllocateVideoMemory.node->VidMem.bytes + : iface.u.AllocateVideoMemory.node->Virtual.bytes; + + CreateVideoMemoryRecord(device->os, + private, + &private->memoryRecordList, + iface.u.AllocateVideoMemory.node, + iface.u.AllocateVideoMemory.type & 0xFF, + bytes); + } + else if (iface.command == gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY) + { + gctSIZE_T bytes = (iface.u.AllocateLinearVideoMemory.node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + ? iface.u.AllocateLinearVideoMemory.node->VidMem.bytes + : iface.u.AllocateLinearVideoMemory.node->Virtual.bytes; + + CreateVideoMemoryRecord(device->os, + private, + &private->memoryRecordList, + iface.u.AllocateLinearVideoMemory.node, + iface.u.AllocateLinearVideoMemory.type & 0xFF, + bytes); + } + else if (iface.command == gcvHAL_FREE_VIDEO_MEMORY) + { + MEMORY_RECORD_PTR mr; + + mr = FindVideoMemoryRecord(device->os, + private, + &private->memoryRecordList, + iface.u.FreeVideoMemory.node); + + if (mr != gcvNULL) + { + DestroyVideoMemoryRecord(device->os, private, mr); + } + else + { + gcmkPRINT("*ERROR* Invalid video memory for free"); + } + } +#endif + + /* Copy data back to the user. */ + copyLen = copy_to_user(drvArgs.OutputBuffer, + &iface, + sizeof(gcsHAL_INTERFACE)); + + if (copyLen != 0) + { + /* The output buffer is not big enough. So fail the I/O. */ + return -ENOTTY; + } + + return 0; +} + +static int drv_mmap(struct file * filp, struct vm_area_struct * vma) +{ + gcsHAL_PRIVATE_DATA_PTR private = filp->private_data; + gckGALDEVICE device; + int ret; + unsigned long size = vma->vm_end - vma->vm_start; + + if (private == gcvNULL) + { + return -ENOTTY; + } + + device = private->device; + + if (device == gcvNULL) + { + return -ENOTTY; + } + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_pgoff = 0; + + if (device->contiguousMapped) + { + ret = io_remap_pfn_range(vma, + vma->vm_start, + (gctUINT32) device->contiguousPhysical >> PAGE_SHIFT, + size, + vma->vm_page_prot); + + private->mappedMemory = (ret == 0) ? (gctPOINTER) vma->vm_start : gcvNULL; + + return ret; + } + else + { + return -ENOTTY; + } +} + + +#if !USE_PLATFORM_DRIVER +static int __init drv_init(void) +#else +static int drv_init(void) +#endif +{ + int ret; + gckGALDEVICE device; + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "Entering drv_init\n"); + + if (showArgs) + { + printk("galcore options:\n"); + printk(" irqLine = %d\n", irqLine); + printk(" registerMemBase = 0x%08lX\n", registerMemBase); + printk(" contiguousSize = %ld\n", contiguousSize); + printk(" contiguousBase = 0x%08lX\n", contiguousBase); + printk(" bankSize = 0x%08lX\n", bankSize); + printk(" fastClear = %d\n", fastClear); + printk(" compression = %d\n", compression); + printk(" signal = %d\n", signal); + printk(" baseAddress = 0x%08lX\n", baseAddress); + } + + /* Create the GAL device. */ + gcmkVERIFY_OK(gckGALDEVICE_Construct(irqLine, + registerMemBase, + registerMemSize, + contiguousBase, + contiguousSize, + bankSize, + fastClear, + compression, + baseAddress, + signal, + &device)); + + /* Start the GAL device. */ + if (gcmIS_ERROR(gckGALDEVICE_Start(device))) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Can't start the gal device.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(device); + gckGALDEVICE_Destroy(device); + + return -1; + } + + /* Register the character device. */ + ret = register_chrdev(major, DRV_NAME, &driver_fops); + if (ret < 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "[galcore] Could not allocate major number for mmap.\n"); + + /* Roll back. */ + gckGALDEVICE_Stop(device); + gckGALDEVICE_Destroy(device); + + return -1; + } + else + { + if (major == 0) + { + major = ret; + } + } + + galDevice = device; + + gpuClass = class_create(THIS_MODULE, "graphics_class"); + if (IS_ERR(gpuClass)) { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DRIVER, + "Failed to create the class.\n"); + return -1; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + device_create(gpuClass, NULL, MKDEV(major, 0), NULL, "galcore"); +#else + device_create(gpuClass, NULL, MKDEV(major, 0), "galcore"); +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "[galcore] irqLine->%ld, contiguousSize->%lu, memBase->0x%lX\n", + irqLine, + contiguousSize, + registerMemBase); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] driver registered successfully.\n"); + + return 0; +} + +#if !USE_PLATFORM_DRIVER +static void __exit drv_exit(void) +#else +static void drv_exit(void) +#endif +{ + struct clk *clk = galDevice->clk; + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_DRIVER, + "[galcore] Entering drv_exit\n"); + + device_destroy(gpuClass, MKDEV(major, 0)); + class_destroy(gpuClass); + + unregister_chrdev(major, DRV_NAME); + + gckGALDEVICE_Stop(galDevice); + gckGALDEVICE_Destroy(galDevice); + + clk_disable(clk); + clk_put(clk); +} + +#if !USE_PLATFORM_DRIVER +module_init(drv_init); +module_exit(drv_exit); +#else + +#ifdef CONFIG_DOVE_GPU +#define DEVICE_NAME "dove_gpu" +#else +#define DEVICE_NAME "galcore" +#endif + + +static int __devinit gpu_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct resource *res; + struct clk *clk; + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,"gpu_irq"); + if (!res) { + printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + irqLine = res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM,"gpu_base"); + if (!res) { + printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + registerMemBase = res->start; + registerMemSize = res->end - res->start + 1; + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA,"gpu_mem"); + if (!res) { + printk(KERN_ERR "%s: No memory base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + contiguousBase = res->start; + contiguousSize = res->end - res->start + 1; + + dev_info(&pdev->dev, "driver v2.5.3.2.2.p3, initializing\n"); + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(clk); + goto gpu_probe_fail; + } + clk_enable(clk); + + ret = drv_init(); + if(!ret) { + platform_set_drvdata(pdev,galDevice); + galDevice->clk = clk; + + dev_info(&pdev->dev, "GPU initialized, clocked at %luMHz\n", + clk_get_rate(clk) / 1000000); + + return ret; + } + + clk_disable(clk); + clk_put(clk); + +gpu_probe_fail: + printk(KERN_INFO "Failed to register gpu driver.\n"); + return ret; +} + +static int __devinit gpu_remove(struct platform_device *pdev) +{ + drv_exit(); + + return 0; +} + +static int __devinit gpu_suspend(struct platform_device *dev, pm_message_t state) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = platform_get_drvdata(dev); + + status = gckHARDWARE_SetPowerManagementState(device->kernel->hardware, gcvPOWER_OFF); + + if (gcmIS_ERROR(status)) + { + return -1; + } + + clk_disable(galDevice->clk); + + return 0; +} + +static int __devinit gpu_resume(struct platform_device *dev) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = platform_get_drvdata(dev); + + clk_enable(galDevice->clk); + + status = gckHARDWARE_SetPowerManagementState(device->kernel->hardware, gcvPOWER_ON); + + if (gcmIS_ERROR(status)) + { + return -1; + } + + status = gckHARDWARE_SetPowerManagementState(device->kernel->hardware, gcvPOWER_IDLE_BROADCAST); + + if (gcmIS_ERROR(status)) + { + return -1; + } + + return 0; +} + +static struct platform_driver gpu_driver = { + .probe = gpu_probe, + .remove = gpu_remove, + + .suspend = gpu_suspend, + .resume = gpu_resume, + + .driver = { + .name = DEVICE_NAME, + } +}; + +static int __init gpu_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&gpu_driver); + return ret; +} + +static void __exit gpu_exit(void) +{ + platform_driver_unregister(&gpu_driver); +} + +module_init(gpu_init); +module_exit(gpu_exit); + +#endif + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.c b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.c new file mode 100644 index 0000000..14f2aa4 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.c @@ -0,0 +1,411 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_QueryVideoMemory +** +** Query the amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to an gcsHAL_INTERFACE structure that will be filled in with +** the memory information. +*/ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT gcsHAL_INTERFACE * Interface + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interface != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Get internal memory size and physical address. */ + Interface->u.QueryVideoMemory.internalSize = device->internalSize; + Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysical; + + /* Get external memory size and physical address. */ + Interface->u.QueryVideoMemory.externalSize = device->externalSize; + Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysical; + + /* Get contiguous memory size and physical address. */ + Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; + Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysical; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_GetVideoMemoryPool +** +** Get the gckVIDMEM object belonging to the specified pool. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcePOOL Pool +** Pool to query gckVIDMEM object for. +** +** OUTPUT: +** +** gckVIDMEM * VideoMemory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object belonging to the requested pool. +*/ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ) +{ + gckGALDEVICE device; + gckVIDMEM videoMemory; + + gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(VideoMemory != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Dispatch on pool. */ + switch (Pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + videoMemory = device->internalVidMem; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + videoMemory = device->externalVidMem; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + videoMemory = device->contiguousVidMem; + break; + + default: + /* Unknown pool. */ + videoMemory = NULL; + } + + /* Return pointer to the gckVIDMEM object. */ + *VideoMemory = videoMemory; + + /* Return status. */ + gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory); + return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_MapMemory +** +** Map video memory into the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the base address of the mapped +** memory region. +*/ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + return gckOS_MapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_UnmapMemory +** +** Unmap video memory from the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** gctPOINTER Logical +** Base address of the mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + return gckOS_UnmapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_MapVideoMemory +** +** Get the logical address for a hardware specific memory address for the +** current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL InUserSpace +** gcvTRUE to map the memory into the user space. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** specified memory address. +*/ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, + OUT gctPOINTER * Logical + ) +{ + gckGALDEVICE device; + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gcePOOL pool; + gctUINT32 offset, base; + gceSTATUS status; + gctPOINTER logical; + + gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Address=%08x", + Kernel, InUserSpace, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Split the memory address into a pool type and offset. */ + gcmkONERROR( + gckHARDWARE_SplitMemory(Kernel->hardware, Address, &pool, &offset)); + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + if (device->contiguousMapped) + { + logical = device->contiguousBase; + } + else + { + mdl = (PLINUX_MDL) device->contiguousPhysical; + + mdlMap = FindMdlMap(mdl, current->tgid); + gcmkASSERT(mdlMap); + + logical = (gctPOINTER) mdlMap->vmaAddr; + } + + gcmkVERIFY_OK( + gckHARDWARE_SplitMemory(Kernel->hardware, + device->contiguousVidMem->baseAddress, + &pool, + &base)); + + offset -= base; + break; + + default: + /* Invalid memory pool. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Build logical address of specified address. */ + *Logical = (gctPOINTER) ((gctUINT8_PTR) logical + offset); + + /* Success. */ + gcmkFOOTER_ARG("*Logical=%p", *Logical); + return gcvSTATUS_OK; + +OnError: + /* Retunn the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Notify +** +** This function iscalled by clients to notify the gckKERNRL object of an event. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gceNOTIFY Notification +** Notification event. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notification, + IN gctBOOL Data + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", + Kernel, Notification, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Dispatch on notifcation. */ + switch (Notification) + { + case gcvNOTIFY_INTERRUPT: + /* Process the interrupt. */ +#if COMMAND_PROCESSOR_VERSION > 1 + status = gckINTERRUPT_Notify(Kernel->interrupt, Data); +#else + status = gckHARDWARE_Interrupt(Kernel->hardware, Data); +#endif + break; + + default: + status = gcvSTATUS_OK; + break; + } + + /* Success. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Settings != gcvNULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Fill in signal. */ + Settings->signal = device->signal; + + /* Success. */ + gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); + return gcvSTATUS_OK; +} + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.h b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.h new file mode 100644 index 0000000..a013715 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_linux.h @@ -0,0 +1,89 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_linux_h_ +#define __gc_hal_kernel_linux_h_ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/signal.h> +#ifdef FLAREON +# include <asm/arch-realview/dove_gpio_irq.h> +#endif +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/dma-mapping.h> +#include <linux/kthread.h> + +#ifdef MODVERSIONS +# include <linux/modversions.h> +#endif +#include <asm/io.h> +#include <asm/uaccess.h> + +#if ENABLE_GPU_CLOCK_BY_DRIVER && LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) +#include <linux/clk.h> +#endif + +#define NTSTRSAFE_NO_CCH_FUNCTIONS +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" +#include "gc_hal_kernel_device.h" +#include "gc_hal_kernel_os.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) +#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#define FIND_TASK_BY_PID(x) find_task_by_vpid(x) +#else +#define FIND_TASK_BY_PID(x) find_task_by_pid(x) +#endif + +#define _WIDE(string) L##string +#define WIDE(string) _WIDE(string) + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +#define DRV_NAME "galcore" + +#define GetPageCount(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) + +static inline gctINT +GetOrder( + IN gctINT numPages + ) +{ + gctINT order = 0; + + while ((1 << order) < numPages) order++; + + return order; +} + +#endif /* __gc_hal_kernel_linux_h_ */ + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.c b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.c new file mode 100644 index 0000000..68fe846 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -0,0 +1,6213 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#include <linux/pagemap.h> +#include <linux/seq_file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <asm/atomic.h> +#ifdef NO_DMA_COHERENT +#include <linux/dma-mapping.h> +#endif /* NO_DMA_COHERENT */ + +#if !USE_NEW_LINUX_SIGNAL +#define USER_SIGNAL_TABLE_LEN_INIT 64 +#endif + +#define _GC_OBJ_ZONE gcvZONE_OS + +#define MEMORY_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryLock, \ + gcvINFINITE)) + +#define MEMORY_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock)) + +#define MEMORY_MAP_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryMapLock, \ + gcvINFINITE)) + +#define MEMORY_MAP_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock)) + +#if gcdkREPORT_VIDMEM_USAGE +static char * _MemTypes[gcvSURF_NUM_TYPES] = +{ + "UNKNOWN", /* gcvSURF_TYPE_UNKNOWN */ + "INDEX", /* gcvSURF_INDEX */ + "VERTEX", /* gcvSURF_VERTEX */ + "TEXTURE", /* gcvSURF_TEXTURE */ + "RT", /* gcvSURF_RENDER_TARGET */ + "DEPTH", /* gcvSURF_DEPTH */ + "BITMAP", /* gcvSURF_BITMAP */ + "TILE_STA", /* gcvSURF_TILE_STATUS */ + "MASK", /* gcvSURF_MASK */ + "SCISSOR", /* gcvSURF_SCISSOR */ + "HZ" /* gcvSURF_HIERARCHICAL_DEPTH */ +}; +#endif + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +struct _gckOS +{ + /* Object. */ + gcsOBJECT object; + + /* Heap. */ + gckHEAP heap; + + /* Pointer to device */ + gckGALDEVICE device; + + /* Memory management */ + gctPOINTER memoryLock; + gctPOINTER memoryMapLock; + + struct _LINUX_MDL *mdlHead; + struct _LINUX_MDL *mdlTail; + + gctUINT32 baseAddress; + + /* Kernel process ID. */ + gctUINT32 kernelProcessID; + +#if !USE_NEW_LINUX_SIGNAL + /* Signal management. */ + struct _signal { + /* Unused signal ID number. */ + gctINT unused; + + /* The pointer to the table. */ + gctPOINTER * table; + + /* Signal table length. */ + gctINT tableLen; + + /* The current unused signal ID. */ + gctINT currentID; + + /* Lock. */ + gctPOINTER lock; + } signal; +#endif +}; + +#if !USE_NEW_LINUX_SIGNAL +typedef struct _gcsSIGNAL +{ + /* Kernel sync primitive. */ + struct completion event; + + /* Manual reset flag. */ + gctBOOL manualReset; + + /* The reference counter. */ + atomic_t ref; + + /* The owner of the signal. */ + gctHANDLE process; +} +gcsSIGNAL; + +typedef struct _gcsSIGNAL * gcsSIGNAL_PTR; +#endif + +typedef struct _gcsPageInfo * gcsPageInfo_PTR; + +typedef struct _gcsPageInfo +{ + struct page **pages; + gctUINT32_PTR pageTable; +} +gcsPageInfo; + + +static PLINUX_MDL +_CreateMdl( + IN gctINT PID + ) +{ + PLINUX_MDL mdl; + + mdl = (PLINUX_MDL)kmalloc(sizeof(struct _LINUX_MDL), GFP_ATOMIC); + if (mdl == gcvNULL) return gcvNULL; + + mdl->pid = PID; + mdl->maps = gcvNULL; + mdl->prev = gcvNULL; + mdl->next = gcvNULL; + + return mdl; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ); + +static gceSTATUS +_DestroyMdl( + IN PLINUX_MDL Mdl + ) +{ + PLINUX_MDL_MAP mdlMap, next; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Mdl != gcvNULL); + + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + next = mdlMap->next; + + gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap)); + + mdlMap = next; + } + + kfree(Mdl); + + return gcvSTATUS_OK; +} + +static PLINUX_MDL_MAP +_CreateMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ) +{ + PLINUX_MDL_MAP mdlMap; + + mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_ATOMIC); + if (mdlMap == gcvNULL) return gcvNULL; + + mdlMap->pid = PID; + mdlMap->vmaAddr = gcvNULL; + mdlMap->vma = gcvNULL; + + mdlMap->next = Mdl->maps; + Mdl->maps = mdlMap; + + return mdlMap; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ) +{ + PLINUX_MDL_MAP prevMdlMap; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL); + gcmkASSERT(Mdl->maps != gcvNULL); + + if (Mdl->maps == MdlMap) + { + Mdl->maps = MdlMap->next; + } + else + { + prevMdlMap = Mdl->maps; + + while (prevMdlMap->next != MdlMap) + { + prevMdlMap = prevMdlMap->next; + + gcmkASSERT(prevMdlMap != gcvNULL); + } + + prevMdlMap->next = MdlMap->next; + } + + kfree(MdlMap); + + return gcvSTATUS_OK; +} + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ) +{ + PLINUX_MDL_MAP mdlMap; + + if (Mdl == gcvNULL) + { + return gcvNULL; + } + + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->pid == PID) return mdlMap; + + mdlMap = mdlMap->next; + } + + return gcvNULL; +} + +void +FreeProcessMemoryOnExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + PLINUX_MDL mdl, nextMdl; + PLINUX_MDL_MAP mdlMap; + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl != Os->mdlTail) + { + nextMdl = mdl->next; + } + else + { + nextMdl = gcvNULL; + } + + if (mdl->pagedMem) + { + mdlMap = mdl->maps; + + if (mdlMap != gcvNULL + && mdlMap->pid == current->tgid + && mdlMap->next == gcvNULL) + { + MEMORY_UNLOCK(Os); + + gcmkVERIFY_OK(gckOS_FreePagedMemory(Os, mdl, mdl->numPages * PAGE_SIZE)); + + MEMORY_LOCK(Os); + + nextMdl = Os->mdlHead; + } + } + + mdl = nextMdl; + } + + MEMORY_UNLOCK(Os); +} + +void +PrintInfoOnExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + PLINUX_MDL mdl, nextMdl; + PLINUX_MDL_MAP mdlMap; + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl != Os->mdlTail) + { + nextMdl = mdl->next; + } + else + { + nextMdl = gcvNULL; + } + + printk("Unfreed mdl: %p, pid: %d -> pagedMem: %s, addr: %p, dmaHandle: 0x%x, pages: %d", + mdl, + mdl->pid, + mdl->pagedMem? "true" : "false", + mdl->addr, + mdl->dmaHandle, + mdl->numPages); + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + printk("\tmap: %p, pid: %d -> vmaAddr: %p, vma: %p", + mdlMap, + mdlMap->pid, + mdlMap->vmaAddr, + mdlMap->vma); + + mdlMap = mdlMap->next; + } + + mdl = nextMdl; + } + + MEMORY_UNLOCK(Os); +} + +void +OnProcessExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ + /* PrintInfoOnExit(Os, Kernel); */ + +#ifdef ANDROID + FreeProcessMemoryOnExit(Os, Kernel); +#endif +} + +/******************************************************************************* +** +** gckOS_Construct +** +** Construct a new gckOS object. +** +** INPUT: +** +** gctPOINTER Context +** Pointer to the gckGALDEVICE class. +** +** OUTPUT: +** +** gckOS * Os +** Pointer to a variable that will hold the pointer to the gckOS object. +*/ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ) +{ + gckOS os; + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Os != gcvNULL); + + /* Allocate the gckOS object. */ + os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_ATOMIC); + + if (os == gcvNULL) + { + /* Out of memory. */ + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Zero the memory. */ + gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS)); + + /* Initialize the gckOS object. */ + os->object.type = gcvOBJ_OS; + + /* Set device device. */ + os->device = Context; + + /* IMPORTANT! No heap yet. */ + os->heap = gcvNULL; + + /* Initialize the memory lock. */ + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryLock)); + + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryMapLock)); + + /* Create the gckHEAP object. */ + gcmkONERROR(gckHEAP_Construct(os, gcdHEAP_SIZE, &os->heap)); + + os->mdlHead = os->mdlTail = gcvNULL; + + /* Find the base address of the physical memory. */ + os->baseAddress = os->device->baseAddress; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "Physical base address set to 0x%08X.", + os->baseAddress); + + /* Get the kernel process ID. */ + gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID)); + +#if !USE_NEW_LINUX_SIGNAL + /* + * Initialize the signal manager. + * It creates the signals to be used in + * the user space. + */ + + /* Initialize mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &os->signal.lock)); + + /* Initialize the signal table. */ + os->signal.table = + kmalloc(gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT, GFP_KERNEL); + + if (os->signal.table == gcvNULL) + { + /* Out of memory. */ + status = gcvSTATUS_OUT_OF_MEMORY; + goto OnError; + } + + gckOS_ZeroMemory(os->signal.table, + gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + + /* Set the signal table length. */ + os->signal.tableLen = USER_SIGNAL_TABLE_LEN_INIT; + + /* The table is empty. */ + os->signal.unused = os->signal.tableLen; + + /* Initial signal ID. */ + os->signal.currentID = 0; +#endif + + /* Return pointer to the gckOS object. */ + *Os = os; + + /* Success. */ + return gcvSTATUS_OK; + +OnError: +#if !USE_NEW_LINUX_SIGNAL + /* Roll back any allocation. */ + if (os->signal.table != gcvNULL) + { + kfree(os->signal.table); + } + + if (os->signal.lock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->signal.lock)); + } +#endif + + if (os->heap != gcvNULL) + { + gcmkVERIFY_OK( + gckHEAP_Destroy(os->heap)); + } + + if (os->memoryMapLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryMapLock)); + } + + if (os->memoryLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryLock)); + } + + kfree(os); + + /* Return the error. */ + return status; +} + +/******************************************************************************* +** +** gckOS_Destroy +** +** Destroy an gckOS object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ) +{ + gckHEAP heap = gcvNULL; + gctINT i = 0; + gctPOINTER *table = Os->signal.table; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + +#if !USE_NEW_LINUX_SIGNAL + /* + * Destroy the signal manager. + */ + + /* Destroy the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->signal.lock)); + + /* Free remain signal left in table */ + for (i = 0; i < Os->signal.tableLen; i++) + { + if(table[i] != gcvNULL) + { + kfree(table[i]); + table[i] = gcvNULL; + } + } + + /* Free the signal table. */ + kfree(Os->signal.table); + Os->signal.table = gcvNULL; + Os->signal.tableLen = 0; +#endif + + if (Os->heap != NULL) + { + /* Mark gckHEAP as gone. */ + heap = Os->heap; + Os->heap = NULL; + + /* Destroy the gckHEAP object. */ + gcmkVERIFY_OK( + gckHEAP_Destroy(heap)); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to destroy signal, it was not unmampped \n" + ); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Destroy the memory lock. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryMapLock)); + + gcmkVERIFY_OK( + gckOS_DeleteMutex(Os, Os->memoryLock)); + + gcmkPRINT("$$FLUSH$$"); + + /* Mark the gckOS object as unknown. */ + Os->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckOS object. */ + kfree(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Allocate +** +** Allocate memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gceSTATUS status; + + /* gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); */ + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Allocate from the heap. */ + gcmkONERROR(gckHEAP_Allocate(Os->heap, Bytes, Memory)); + } + else + { + gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory)); + } + + /* Success. */ + /* gcmkFOOTER_ARG("*memory=0x%x", *Memory); */ + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_Free +** +** Free allocated memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gceSTATUS status; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* gcmkHEADER_ARG("Os=0x%x Memory=0x%x", Os, memory); */ + + /* Do we have a heap? */ + if (Os->heap != NULL) + { + /* Free from the heap. */ + gcmkONERROR(gckHEAP_Free(Os->heap, Memory)); + } + else + { + gcmkONERROR(gckOS_FreeMemory(Os, Memory)); + } + + /* Success. */ + /* gcmkFOOTER_NO(); */ + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AllocateMemory +** +** Allocate memory wrapper. +** +** INPUT: +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctPOINTER memory; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + memory = (gctPOINTER) kmalloc(Bytes, GFP_ATOMIC); + + if (memory == NULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the memory allocation. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=%p", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeMemory +** +** Free allocated memory wrapper. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gcmkHEADER_ARG("Memory=%p", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Free the memory from the OS pool. */ + kfree(Memory); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateVirtualMemory +** +** Allocate virtual memory wrapper. +** +** INPUT: +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_AllocateVirtualMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctPOINTER memory; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != NULL); + + memory = (gctPOINTER) vmalloc(Bytes); + + if (memory == NULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the memory allocation. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=%p", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeVirtualMemory +** +** Free allocated virtual memory wrapper. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeVirtualMemory( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gcmkHEADER_ARG("Memory=%p", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Memory != NULL); + + /* Free the memory from the OS pool. */ + vfree(Memory); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapMemory +** +** Map physical memory into the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the logical address of the +** mapped memory. +*/ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (char *)do_mmap_pgoff(NULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: do_mmap_pgoff error"); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapMemory] mdl->numPages: %d", + "[gckOS_MapMemory] mdl->vmaAddr: 0x%x", + mdl->numPages, + mdlMap->vmaAddr + ); + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (!mdlMap->vma) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: find_vma error."); + + mdlMap->vmaAddr = gcvNULL; + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(NULL, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: dma_mmap_coherent error."); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#else + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages*PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_MapMemory: remap_pfn_range error."); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#endif + + up_write(¤t->mm->mmap_sem); + } + + MEMORY_UNLOCK(Os); + + *Logical = mdlMap->vmaAddr; + + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_OS, + "gckOS_MapMemory: User Mapped address for 0x%x is 0x%x pid->%d", + (gctUINT32)mdl->addr, + (gctUINT32)*Logical, + mdlMap->pid); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapMemory +** +** Unmap physical memory out of the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** gctPOINTER Memory +** Pointer to a previously mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnmapMemory"); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_UnmapMemory Will be unmapping 0x%x mdl->0x%x", + (gctUINT32)Logical, + (gctUINT32)mdl); + + MEMORY_LOCK(Os); + + if (Logical) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapMemory] Logical: 0x%x", + Logical + ); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)Logical, mdl->numPages*PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "Can't find the task with pid->%d. No unmapping", + mdlMap->pid); + } + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateNonPagedMemory +** +** Allocate a number of pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to a variable that holds the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that hold the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that will hold the physical address of the +** allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** allocation. +*/ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + gctSIZE_T bytes; + gctINT numPages; + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap = 0; + gctSTRING addr; + +#ifdef NO_DMA_COHERENT + struct page * page; + long size, order; + gctPOINTER vaddr, reserved_vaddr; + gctUINT32 reserved_size; +#endif + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT((Bytes != NULL) && (*Bytes > 0)); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_AllocateNonPagedMemory"); + + /* Align number of bytes to page size. */ + bytes = gcmALIGN(*Bytes, PAGE_SIZE); + + /* Get total number of pages.. */ + numPages = GetPageCount(bytes, 0); + + /* Allocate mdl+vector structure */ + mdl = _CreateMdl(current->tgid); + + if (mdl == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl->pagedMem = 0; + mdl->numPages = numPages; + + MEMORY_LOCK(Os); + +#ifndef NO_DMA_COHERENT + addr = dma_alloc_coherent(NULL, + mdl->numPages * PAGE_SIZE, + &mdl->dmaHandle, + GFP_ATOMIC); +#else + size = mdl->numPages * PAGE_SIZE; + order = get_order(size); + page = alloc_pages(GFP_KERNEL, order); + + if (page == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* + * On some system ioremap_nocache fails when + * given a size of more than 1 page if all + * of the pages haven't been marked as reserved + * first. Allocating a single page works without + * any changes though. + */ + vaddr = (gctPOINTER)page_address(page); + + reserved_vaddr = vaddr; + reserved_size = size; + + while (reserved_size > 0) + { + SetPageReserved(virt_to_page(reserved_vaddr)); + + reserved_vaddr += PAGE_SIZE; + reserved_size -= PAGE_SIZE; + } + + addr = ioremap_nocache(virt_to_phys(vaddr), size); + mdl->dmaHandle = virt_to_phys(vaddr); + mdl->kaddr = vaddr; + +#if ENABLE_ARM_L2_CACHE + dma_cache_maint(vaddr, size, DMA_FROM_DEVICE); +#endif + +#endif + + if (addr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "galcore: Can't allocate memorry for size->0x%x", + (gctUINT32)bytes); + + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + if ((Os->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000)) + { + mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000) + | (Os->baseAddress & 0x80000000); + } + + mdl->addr = addr; + + /* + * We will not do any mapping from here. + * Mapping will happen from mmap method. + * mdl structure will be used. + */ + + /* Return allocated memory. */ + *Bytes = bytes; + *Physical = (gctPHYS_ADDR) mdl; + + if (InUserSpace) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Only after mmap this will be valid. */ + + /* We need to map this to user space. */ + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(gcvNULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "galcore: do_mmap_pgoff error"); + + up_write(¤t->mm->mmap_sem); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "find_vma error"); + + up_write(¤t->mm->mmap_sem); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(NULL, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "dma_mmap_coherent error"); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#else + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages * PAGE_SIZE, + mdlMap->vma->vm_page_prot)) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "remap_pfn_range error"); + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } +#endif /* NO_DMA_COHERENT */ + + up_write(¤t->mm->mmap_sem); + + *Logical = mdlMap->vmaAddr; + } + else + { + *Logical = (gctPOINTER)mdl->addr; + } + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to the tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocateNonPagedMemory: " + "Bytes->0x%x, Mdl->%p, Logical->0x%x dmaHandle->0x%x", + (gctUINT32)bytes, + mdl, + (gctUINT32)mdl->addr, + mdl->dmaHandle); + + if (InUserSpace) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "vmaAddr->0x%x pid->%d", + (gctUINT32)mdlMap->vmaAddr, + mdlMap->pid); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreeNonPagedMemory +** +** Free previously allocated and mapped pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes allocated. +** +** gctPHYS_ADDR Physical +** Physical address of the allocated memory. +** +** gctPOINTER Logical +** Logical address of the allocated memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + struct task_struct * task; + +#ifdef NO_DMA_COHERENT + unsigned size; + gctPOINTER vaddr; +#endif /* NO_DMA_COHERENT */ + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_FreeNonPagedMemory"); + + /* Convert physical address into a pointer to a MDL. */ + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + +#ifndef NO_DMA_COHERENT + dma_free_coherent(gcvNULL, + mdl->numPages * PAGE_SIZE, + mdl->addr, + mdl->dmaHandle); +#else + size = mdl->numPages * PAGE_SIZE; + vaddr = mdl->kaddr; + + while (size > 0) + { + ClearPageReserved(virt_to_page(vaddr)); + + vaddr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE)); + + iounmap(mdl->addr); +#endif /* NO_DMA_COHERENT */ + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->vmaAddr != gcvNULL) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + + if (do_munmap(task->mm, + (unsigned long)mdlMap->vmaAddr, + mdl->numPages * PAGE_SIZE) < 0) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Unmap Failed ->Mdl->0x%x Logical->0x%x vmaAddr->0x%x", + (gctUINT32)mdl, + (gctUINT32)mdl->addr, + (gctUINT32)mdlMap->vmaAddr); + } + + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + /* Remove the node from global list.. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreeNonPagedMemory: " + "Mdl->0x%x Logical->0x%x", + (gctUINT32)mdl, + (gctUINT32)mdl->addr); + + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_ReadRegister +** +** Read data from a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** OUTPUT: +** +** gctUINT32 * Data +** Pointer to a variable that receives the data read from the register. +*/ +gceSTATUS gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Data != NULL); + + *Data = readl((gctUINT8 *)Os->device->registerBase + Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteRegister +** +** Write data to a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ) +{ + writel(Data, (gctUINT8 *)Os->device->registerBase + Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPageSize +** +** Get the system's page size. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctSIZE_T * PageSize +** Pointer to a variable that will receive the system's page size. +*/ +gceSTATUS gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(PageSize != NULL); + + /* Return the page size. */ + *PageSize = (gctSIZE_T) PAGE_SIZE; + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddressProcess +** +** Get the physical system address of a corresponding virtual address for a +** given process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** gctUINT ProcessID +** Procedd ID. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS +gckOS_GetPhysicalAddressProcess( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT ProcessID, + OUT gctUINT32 * Address + ) +{ + return gckOS_GetPhysicalAddress(Os, Logical, Address); +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddress +** +** Get the physical system address of a corresponding virtual address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* + * Try to search the address in our list. + * This could be an mmaped memory. + * Search in our list. + */ + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + /* Check for the logical address match. */ + if (mdl->addr + && (gctUINT32)Logical >= (gctUINT32)mdl->addr + && (gctUINT32)Logical < ((gctUINT32)mdl->addr + mdl->numPages*PAGE_SIZE)) + { + if (mdl->dmaHandle) + { + /* The memory was from coherent area. */ + *Address = (gctUINT32)mdl->dmaHandle + + (gctUINT32)((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + else if (mdl->pagedMem) + { + if (mdl->contiguous) + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + ((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + else + { + *Address = page_to_phys(vmalloc_to_page((gctSTRING)mdl->addr + + ((gctUINT32)Logical - (gctUINT32)mdl->addr))); + } + } + else + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + ((gctUINT32)Logical - (gctUINT32)mdl->addr); + } + break; + } + + mdlMap = FindMdlMap(mdl, current->tgid); + + /* Is the given address within that range. */ + if (mdlMap != gcvNULL + && mdlMap->vmaAddr != gcvNULL + && Logical >= mdlMap->vmaAddr + && Logical < (mdlMap->vmaAddr + mdl->numPages * PAGE_SIZE)) + { + if (mdl->dmaHandle) + { + /* The memory was from coherent area. */ + *Address = (gctUINT32)mdl->dmaHandle + + (gctUINT32)((gctUINT32)Logical + - (gctUINT32)mdlMap->vmaAddr); + } + else if (mdl->pagedMem) + { + if (mdl->contiguous) + { + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + (gctUINT32)(Logical - mdlMap->vmaAddr); + } + else + { + *Address = page_to_phys(vmalloc_to_page((gctSTRING)mdl->addr + + ((gctUINT32)Logical - (gctUINT32)mdlMap->vmaAddr))); + } + } + else + { + /* Return the kernel virtual pointer based on this. */ + *Address = (gctUINT32)virt_to_phys(mdl->addr) + + (gctUINT32)(Logical - mdlMap->vmaAddr); + } + break; + } + + mdl = mdl->next; + } + + /* Subtract base address to get a GPU physical address. */ + gcmkASSERT(*Address >= Os->baseAddress); + *Address -= Os->baseAddress; + + MEMORY_UNLOCK(Os); + + if (mdl == gcvNULL) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPhysical +** +** Map a physical address into kernel space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Physical +** Physical address of the memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the base address of the mapped +** memory. +*/ +gceSTATUS gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + gctPOINTER logical; + PLINUX_MDL mdl; + gctUINT32 physical; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + MEMORY_LOCK(Os); + + /* Compute true physical address (before subtraction of the baseAddress). */ + physical = Physical + Os->baseAddress; + + /* Go through our mapping to see if we know this physical address already. */ + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->dmaHandle != 0) + { + if ((physical >= mdl->dmaHandle) + && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE) + ) + { + *Logical = mdl->addr + (physical - mdl->dmaHandle); + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Map memory as cached memory. */ + request_mem_region(physical, Bytes, "MapRegion"); + logical = (gctPOINTER) ioremap_nocache(physical, Bytes); + + if (logical == NULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "gckOS_MapMemory: Failed to ioremap"); + + MEMORY_UNLOCK(Os); + + /* Out of resources. */ + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Return pointer to mapped memory. */ + *Logical = logical; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "gckOS_MapPhysical: " + "Physical->0x%X Bytes->0x%X Logical->0x%X MappingFound->%d", + (gctUINT32) Physical, + (gctUINT32) Bytes, + (gctUINT32) *Logical, + mdl ? 1 : 0); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapPhysical +** +** Unmap a previously mapped memory region from kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Pointer to the base address of the memory to unmap. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->addr != gcvNULL) + { + if (Logical >= (gctPOINTER)mdl->addr + && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE)) + { + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Unmap the memory. */ + iounmap(Logical); + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_UnmapPhysical: " + "Logical->0x%x Bytes->0x%x MappingFound(?)->%d", + (gctUINT32)Logical, + (gctUINT32)Bytes, + mdl ? 1 : 0); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateMutex +** +** Create a new mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Mutex +** Pointer to a variable that will hold a pointer to the mutex. +*/ +gceSTATUS gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Allocate a FAST_MUTEX structure. */ + *Mutex = (gctPOINTER)kmalloc(sizeof(struct semaphore), GFP_KERNEL); + + if (*Mutex == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Initialize the semaphore.. Come up in unlocked state. */ + sema_init(*Mutex, 1); + + /* Return status. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DeleteMutex +** +** Delete a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mute to be deleted. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Delete the fast mutex. */ + kfree(Mutex); + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AcquireMutex +** +** Acquire a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be acquired. +** +** gctUINT32 Timeout +** Timeout value specified in milliseconds. +** Specify the value of gcvINFINITE to keep the thread suspended +** until the mutex has been acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + if (Timeout == gcvINFINITE) + { + down((struct semaphore *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; + } + + while (gcvTRUE) + { + /* Try to acquire the fast mutex. */ + if (!down_trylock((struct semaphore *) Mutex)) + { + /* Success. */ + return gcvSTATUS_OK; + } + + if (Timeout-- == 0) break; + + /* Wait for 1 millisecond. */ + gcmkVERIFY_OK(gckOS_Delay(Os, 1)); + } + + /* Timeout. */ + return gcvSTATUS_TIMEOUT; +} + +/******************************************************************************* +** +** gckOS_ReleaseMutex +** +** Release an acquired mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != NULL); + + /* Release the fast mutex. */ + up((struct semaphore *) Mutex); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchange +** +** Atomically exchange a pair of 32-bit values. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctINT32_PTR Target +** Pointer to the 32-bit value to exchange. +** +** IN gctINT32 NewValue +** Specifies a new value for the 32-bit value pointed to by Target. +** +** OUT gctINT32_PTR OldValue +** The old value of the 32-bit value pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of 32-bit values. */ + *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchangePtr +** +** Atomically exchange a pair of pointers. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctPOINTER * Target +** Pointer to the 32-bit value to exchange. +** +** IN gctPOINTER NewValue +** Specifies a new value for the pointer pointed to by Target. +** +** OUT gctPOINTER * OldValue +** The old value of the pointer pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of pointers. */ + *OldValue = (gctPOINTER) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Allocate the atom. */ + gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom)); + + /* Initialize the atom. */ + atomic_set((atomic_t *) *Atom, 0); + + /* Success. */ + gcmkFOOTER_ARG("*Atom=0x%x", *Atom); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Free the atom. */ + gcmkONERROR(gckOS_Free(Os, Atom)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Return the current value of atom. */ + *Value = atomic_read((atomic_t *) Atom); + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Increment the atom. */ + *Value = atomic_inc_return((atomic_t *) Atom) - 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%x Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Decrement the atom. */ + *Value = atomic_dec_return((atomic_t *) Atom) + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Delay +** +** Delay execution of the current thread for a number of milliseconds. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Delay +** Delay to sleep, specified in milliseconds. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ) +{ + struct timeval now; + unsigned long jiffies; + + if (Delay > 0) + { + /* Convert milliseconds into seconds and microseconds. */ + now.tv_sec = Delay / 1000; + now.tv_usec = (Delay % 1000) * 1000; + + /* Convert timeval to jiffies. */ + jiffies = timeval_to_jiffies(&now); + + /* Schedule timeout. */ + schedule_timeout_interruptible(jiffies); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MemoryBarrier +** +** Make sure the CPU has executed everything up to this point and the data got +** written to the specified pointer. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of memory that needs to be barriered. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ) +{ + /* Verify thearguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + mb(); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemory +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + return gckOS_AllocatePagedMemoryEx(Os, gcvFALSE, Bytes, Physical); +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemoryEx +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL Contiguous +** Need contiguous memory or not. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + gctINT numPages; + gctINT i; + PLINUX_MDL mdl; + gctSTRING addr; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Os=0x%0x Contiguous=%d Bytes=%lu", Os, Contiguous, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + bytes = gcmALIGN(Bytes, PAGE_SIZE); + + numPages = GetPageCount(bytes, 0); + + MEMORY_LOCK(Os); + + if (Contiguous) + { + addr = (char *)__get_free_pages(GFP_ATOMIC, GetOrder(numPages)); + } + else + { + addr = vmalloc(bytes); + } + + if (!addr) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_AllocatePagedMemoryEx: " + "Can't allocate memorry for size->0x%x", + (gctUINT32)bytes); + + MEMORY_UNLOCK(Os); + + gcmkHEADER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl = _CreateMdl(current->tgid); + + if (mdl == gcvNULL) + { + if (Contiguous) + { + free_pages((unsigned int) addr, GetOrder(mdl->numPages)); + } + else + { + vfree(addr); + } + + MEMORY_UNLOCK(Os); + + gcmkHEADER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdl->dmaHandle = 0; + mdl->addr = addr; + mdl->numPages = numPages; + mdl->pagedMem = 1; + mdl->contiguous = Contiguous; + + for (i = 0; i < mdl->numPages; i++) + { + struct page *page; + + if (mdl->contiguous) + { + page = virt_to_page((void *)(((unsigned long)addr) + i * PAGE_SIZE)); + } + else + { + page = vmalloc_to_page((void *)(((unsigned long)addr) + i * PAGE_SIZE)); + } + + SetPageReserved(page); + flush_dcache_page(page); + } + + /* Return physical address. */ + *Physical = (gctPHYS_ADDR) mdl; + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, + "%s: Bytes=%lu Mdl=0x%08x Logical=0x%08x", + __FUNCTION__, bytes, mdl, mdl->addr); + + /* Success. */ + gcmkHEADER_ARG("*Physical=0x%08x", *Physical); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_FreePagedMemory +** +** Free memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + gctSTRING addr; + gctINT i; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_FreePagedMemory"); + + addr = mdl->addr; + + MEMORY_LOCK(Os); + + for (i = 0; i < mdl->numPages; i++) + { + if (mdl->contiguous) + { + ClearPageReserved(virt_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE))); + } + else + { + ClearPageReserved(vmalloc_to_page((gctPOINTER)(((unsigned long)addr) + i * PAGE_SIZE))); + } + } + + if (mdl->contiguous) + { + free_pages((unsigned long)mdl->addr, GetOrder(mdl->numPages)); + } + else + { + vfree(mdl->addr); + } + + /* Remove the node from global list. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + /* Free the structure... */ + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_FreePagedMemory: Bytes->0x%x, Mdl->0x%x", + (gctUINT32)Bytes, + (gctUINT32)mdl); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_LockPages +** +** Lock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the address of the mapped +** memory. +** +** gctSIZE_T * PageCount +** Pointer to a variable that receives the number of pages required for +** the page table according to the GPU page size. +*/ +gceSTATUS gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gctSTRING addr; + unsigned long start; + unsigned long pfn; + gctINT i; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(PageCount != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_LockPages"); + + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, current->tgid); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(NULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "vmaAddr->0x%x for phys_addr->0x%x", + (gctUINT32)mdlMap->vmaAddr, + (gctUINT32)mdl); + + if (mdlMap->vmaAddr == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: do_mmap_pgoff error"); + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "find_vma error"); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_RESOURCES; + } + + mdlMap->vma->vm_flags |= VM_RESERVED; + /* Make this mapping non-cached. */ + mdlMap->vma->vm_page_prot = pgprot_noncached(mdlMap->vma->vm_page_prot); + + addr = mdl->addr; + + /* Now map all the vmalloc pages to this user address. */ + down_write(¤t->mm->mmap_sem); + + if (mdl->contiguous) + { + /* map kernel memory to user space.. */ + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + virt_to_phys((gctPOINTER)mdl->addr) >> PAGE_SHIFT, + mdlMap->vma->vm_end - mdlMap->vma->vm_start, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: unable to mmap ret"); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + } + else + { + start = mdlMap->vma->vm_start; + + for (i = 0; i < mdl->numPages; i++) + { + pfn = vmalloc_to_pfn(addr); + + if (remap_pfn_range(mdlMap->vma, + start, + pfn, + PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "gctPHYS_ADDR->0x%x Logical->0x%x Unable to map addr->0x%x to start->0x%x", + (gctUINT32)Physical, + (gctUINT32)*Logical, + (gctUINT32)addr, + (gctUINT32)start); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + start += PAGE_SIZE; + addr += PAGE_SIZE; + } + } + + up_write(¤t->mm->mmap_sem); + } + + /* Convert pointer to MDL. */ + *Logical = mdlMap->vmaAddr; + + /* Return the page number according to the GPU page size. */ + gcmkASSERT((PAGE_SIZE % 4096) == 0); + gcmkASSERT((PAGE_SIZE / 4096) >= 1); + + *PageCount = mdl->numPages * (PAGE_SIZE / 4096); + + MEMORY_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_LockPages: " + "gctPHYS_ADDR->0x%x Bytes->0x%x Logical->0x%x pid->%d", + (gctUINT32)Physical, + (gctUINT32)Bytes, + (gctUINT32)*Logical, + mdlMap->pid); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPages +** +** Map paged memory into a page table. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T PageCount +** Number of pages required for the physical address. +** +** gctPOINTER PageTable +** Pointer to the page table to fill in. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ) +{ + PLINUX_MDL mdl; + gctUINT32* table; + gctSTRING addr; + gctINT i = 0; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_MapPages"); + + /* Convert pointer to MDL. */ + mdl = (PLINUX_MDL)Physical; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "gckOS_MapPages: " + "Physical->0x%x PageCount->0x%x PagedMemory->?%d", + (gctUINT32)Physical, + (gctUINT32)PageCount, + mdl->pagedMem); + + MEMORY_LOCK(Os); + + table = (gctUINT32 *)PageTable; + + /* Get all the physical addresses and store them in the page table. */ + + addr = mdl->addr; + + if (mdl->pagedMem) + { + /* Try to get the user pages so DMA can happen. */ + while (PageCount-- > 0) + { + if (mdl->contiguous) + { + *table++ = virt_to_phys(addr); + } + else + { + *table++ = page_to_phys(vmalloc_to_page(addr)); + } + + addr += 4096; + i++; + } + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "We should not get this call for Non Paged Memory!"); + + while (PageCount-- > 0) + { + *table++ = (gctUINT32)virt_to_phys(addr); + addr += 4096; + } + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnlockPages +** +** Unlock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** gctPOINTER Logical +** Address of the mapped memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + /* Make sure there is already a mapping...*/ + gcmkVERIFY_ARGUMENT(mdl->addr != NULL); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "in gckOS_UnlockPages"); + + MEMORY_LOCK(Os); + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->vmaAddr != gcvNULL) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)Logical, mdl->numPages * PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_AllocateContiguous +** +** Allocate memory from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that receives the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that receives the logical address of the +** memory allocation. +*/ +gceSTATUS gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + /* Same as non-paged memory for now. */ + return gckOS_AllocateNonPagedMemory(Os, + InUserSpace, + Bytes, + Physical, + Logical + ); +} + +/******************************************************************************* +** +** gckOS_FreeContiguous +** +** Free memory allocated from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctPOINTER Logical +** Logicval address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + /* Same of non-paged memory for now. */ + return gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical); +} + +/****************************************************************************** +** +** gckOS_GetKernelLogical +** +** Return the kernel logical pointer that corresponods to the specified +** hardware address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Hardware physical address. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the pointer in kernel address space. +*/ +gceSTATUS +gckOS_GetKernelLogical( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + + do + { + gckGALDEVICE device; + gckKERNEL kernel; + gcePOOL pool; + gctUINT32 offset; + gctPOINTER logical; + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Os->device; + + /* Kernel shortcut. */ + kernel = device->kernel; + + /* Split the memory address into a pool type and offset. */ + gcmkERR_BREAK(gckHARDWARE_SplitMemory( + kernel->hardware, Address, &pool, &offset + )); + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + logical = device->contiguousBase; + break; + + default: + /* Invalid memory pool. */ + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Build logical address of specified address. */ + * KernelPointer = ((gctUINT8_PTR) logical) + offset; + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_MapUserPointer +** +** Map a pointer from the user process into the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be mapped. +** +** gctSIZE_T Size +** Number of bytes that need to be mapped. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the mapped pointer in kernel address +** space. +*/ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + gctPOINTER buf = gcvNULL; + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + buf = kmalloc(Size, GFP_KERNEL); + if (buf == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to allocate memory at line %d in %s.", + __LINE__, __FILE__ + ); + + return gcvSTATUS_OUT_OF_MEMORY; + } + + len = copy_from_user(buf, Pointer, Size); + if (len != 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to copy data from user at line %d in %s.", + __LINE__, __FILE__ + ); + + if (buf != gcvNULL) + { + kfree(buf); + } + + return gcvSTATUS_GENERIC_IO; + } + + *KernelPointer = buf; +#else + *KernelPointer = Pointer; +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapUserPointer +** +** Unmap a user process pointer from the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be unmapped. +** +** gctSIZE_T Size +** Number of bytes that need to be unmapped. +** +** gctPOINTER KernelPointer +** Pointer in kernel address space that needs to be unmapped. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ) +{ +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + len = copy_to_user(Pointer, KernelPointer, Size); + + kfree(KernelPointer); + + if (len != 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Failed to copy data to user at line %d in %s.", + __LINE__, __FILE__ + ); + return gcvSTATUS_GENERIC_IO; + } +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteMemory +** +** Write data to a memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of the memory to write to. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != NULL); + + /* Write memory. */ + writel(Data, (gctUINT8 *)Address); + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateSignal +** +** Create a new signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctSIGNAL * Signal +** Pointer to a variable receiving the created gctSIGNAL. +*/ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + /* Create an event structure. */ + signal = (gcsSIGNAL_PTR)kmalloc(sizeof(gcsSIGNAL), GFP_ATOMIC); + + if (signal == gcvNULL) + { + return gcvSTATUS_OUT_OF_MEMORY; + } + + signal->manualReset = ManualReset; + + init_completion(&signal->event); + + atomic_set(&signal->ref, 1); + + *Signal = (gctSIGNAL) signal; + + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckOS_DestroySignal +** +** Destroy a signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != NULL); + + signal = (gcsSIGNAL_PTR) Signal; + + if (atomic_dec_and_test(&signal->ref)) + { + /* Free the sgianl. */ + kfree(Signal); + } + + /* Success. */ + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckOS_Signal +** +** Set a state of the specified signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ) +{ +#if USE_NEW_LINUX_SIGNAL + return gcvSTATUS_NOT_SUPPORTED; +#else + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x State=%d", Os, Signal, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + /* Set the new state of the event. */ + if (signal->manualReset) + { + if (State) + { + /* Set the event to a signaled state. */ + complete_all(&signal->event); + } + else + { + /* Set the event to an unsignaled state. */ + INIT_COMPLETION(signal->event); + } + } + else + { + if (State) + { + /* Set the event to a signaled state. */ + complete(&signal->event); + + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +#endif +} + +#if USE_NEW_LINUX_SIGNAL +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ) +{ + gceSTATUS status; + gctINT result; + struct task_struct * task; + struct siginfo info; + + task = FIND_TASK_BY_PID((pid_t) Process); + + if (task != gcvNULL) + { + /* Fill in the siginfo structure. */ + info.si_signo = Os->device->signal; + info.si_errno = 0; + info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); + info.si_ptr = Signal; + + /* Send the signal. */ + if ((result = send_sig_info(Os->device->signal, &info, task)) < 0) + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): send_sig_info failed.", + __FUNCTION__, __LINE__); + } + else + { + /* Success. */ + status = gcvSTATUS_OK; + } + } + else + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE(gcvLEVEL_ERROR, + "%s(%d): find_task_by_pid failed.", + __FUNCTION__, __LINE__); + } + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + return gcvSTATUS_NOT_SUPPORTED; +} + +/******************************************************************************* +** +** gckOS_UnmapSignal +** +** Unmap a signal . +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to that gctSIGNAL mapped. +*/ +gceSTATUS +gckOS_UnmapSignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + return gcvSTATUS_NOT_SUPPORTED; +} + +#else + +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctSIGNAL signal = gcvNULL; + gctBOOL mapped = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x Signal=%d Process=0x%x", + Os, (gctINT) Signal, Process); + + /* Map the signal into kernel space. */ + gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal)); + mapped = gcvTRUE; + + /* Signal. */ + status = gckOS_Signal(Os, signal, gcvTRUE); + + /* Unmap the signal */ + gcmkONERROR(gckOS_UnmapSignal(Os, signal)); + mapped = gcvFALSE; + + gcmkFOOTER(); + return status; + +OnError: + if (mapped) + { + gcmkONERROR(gckOS_UnmapSignal(Os, signal)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctUINT timeout; + gctUINT rc; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x Wait=%u", Os, Signal, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + /* Convert wait to milliseconds. */ + timeout = (Wait == gcvINFINITE) ? MAX_SCHEDULE_TIMEOUT : Wait*HZ/1000; + + /* Linux bug ? */ + if (!signal->manualReset && timeout == 0) timeout = 1; + + rc = wait_for_completion_interruptible_timeout(&signal->event, timeout); + status = ((rc == 0) && !signal->event.done) ? gcvSTATUS_TIMEOUT + : gcvSTATUS_OK; + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignalUninterruptible +** +** Wait for a signal to become signaled uninterruptibly. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignalUninterruptible( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctUINT timeout; + gctUINT rc; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x Wait=%u", Os, Signal, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + /* Convert wait to milliseconds. */ + timeout = (Wait == gcvINFINITE) ? MAX_SCHEDULE_TIMEOUT : Wait*HZ/1000; + + /* Linux bug ? */ + if (!signal->manualReset && timeout == 0) timeout = 1; + + rc = wait_for_completion_timeout(&signal->event, timeout); + status = ((rc == 0) && !signal->event.done) ? gcvSTATUS_TIMEOUT + : gcvSTATUS_OK; + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + gctINT signalID; + gcsSIGNAL_PTR signal; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x Signal=0x%x Process=0x%x", Os, Signal, Process); + + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL); + + signalID = (gctINT) Signal - 1; + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (signalID >= 0 && signalID < Os->signal.tableLen) + { + /* It is a user space signal. */ + signal = Os->signal.table[signalID]; + + if (signal == gcvNULL) + { + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + } + else + { + /* It is a kernel space signal structure. */ + signal = (gcsSIGNAL_PTR) Signal; + } + + if (atomic_inc_return(&signal->ref) <= 1) + { + /* The previous value is 0, it has been deleted. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + + *MappedSignal = (gctSIGNAL) signal; + + /* Success. */ + gcmkFOOTER_ARG("*MappedSignal=0x%x", *MappedSignal); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_UnmapSignal +** +** Unmap a signal . +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to that gctSIGNAL mapped. +*/ +gceSTATUS +gckOS_UnmapSignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctBOOL acquired = gcvFALSE; + gcsSIGNAL_PTR signal = (gcsSIGNAL_PTR)Signal; + + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (atomic_dec_return(&signal->ref) < 1) + { + /* The previous value is less than 1, it hasn't been mapped. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_CreateUserSignal +** +** Create a new signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctINT * SignalID +** Pointer to a variable receiving the created signal's ID. +*/ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ) +{ + gcsSIGNAL_PTR signal; + gctINT unused, currentID, tableLen; + gctPOINTER * table; + gctINT i; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%0x ManualReset=%d", Os, ManualReset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(SignalID != gcvNULL); + + /* Lock the table. */ + gcmkONERROR( + gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Os->signal.unused < 1) + { + /* Enlarge the table. */ + table = (gctPOINTER *) kmalloc( + sizeof(gctPOINTER) * (Os->signal.tableLen + USER_SIGNAL_TABLE_LEN_INIT), + GFP_KERNEL); + + if (table == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + memset(table + Os->signal.tableLen, 0, sizeof(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + memcpy(table, Os->signal.table, sizeof(gctPOINTER) * Os->signal.tableLen); + + /* Release the old table. */ + kfree(Os->signal.table); + + /* Update the table. */ + Os->signal.table = table; + Os->signal.currentID = Os->signal.tableLen; + Os->signal.tableLen += USER_SIGNAL_TABLE_LEN_INIT; + Os->signal.unused += USER_SIGNAL_TABLE_LEN_INIT; + } + + table = Os->signal.table; + currentID = Os->signal.currentID; + tableLen = Os->signal.tableLen; + unused = Os->signal.unused; + + /* Create a new signal. */ + gcmkONERROR( + gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal)); + + /* Save the process ID. */ + signal->process = (gctHANDLE) current->tgid; + + table[currentID] = signal; + + /* Plus 1 to avoid NULL claims. */ + *SignalID = currentID + 1; + + /* Update the currentID. */ + if (--unused > 0) + { + for (i = 0; i < tableLen; i++) + { + if (++currentID >= tableLen) + { + /* Wrap to the begin. */ + currentID = 0; + } + + if (table[currentID] == gcvNULL) + { + break; + } + } + } + + Os->signal.table = table; + Os->signal.currentID = currentID; + Os->signal.tableLen = tableLen; + Os->signal.unused = unused; + + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + gcmkFOOTER_ARG("*SignalID=%d", gcmOPT_VALUE(SignalID)); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_DestroyUserSignal +** +** Destroy a signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** The signal's ID. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d", Os, SignalID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR( + gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: invalid signal->%d.", + (gctINT) SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Check to see if the process is the owner of the signal. */ + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: process id doesn't match. ", + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + gcmkONERROR( + gckOS_DestroySignal(Os, signal)); + + /* Update the table. */ + Os->signal.table[SignalID] = gcvNULL; + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = SignalID; + } + + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitUserSignal +** +** Wait for a signal used in the user mode to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** Signal ID. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d Wait=%u", Os, SignalID, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: invalid signal.", + SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitUserSignal: process id doesn't match. " + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + +do{ + status = gckOS_WaitSignal(Os, signal, Wait==gcvINFINITE?5000:Wait); +if(Wait==gcvINFINITE&&status==gcvSTATUS_TIMEOUT){gcmkPRINT("$$FLUSH$$");} +}while(status==gcvSTATUS_TIMEOUT&&Wait==gcvINFINITE); + + /* Return the status. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_SignalUserSignal +** +** Set a state of the specified signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** SignalID. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%x SignalID=%d State=%d", Os, SignalID, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if ((SignalID < 1) + || (SignalID > Os->signal.tableLen) + ) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_OS, + "gckOS_WaitSignal: invalid signal->%d.", SignalID); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_WaitSignal: signal is NULL." + ); + + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + + if (signal->process != (gctHANDLE) current->tgid) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "gckOS_DestroyUserSignal: process id doesn't match. ", + "signal->process: %d, current->tgid: %d", + signal->process, + current->tgid); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + status = gckOS_Signal(Os, signal, State); + + /* Success. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckOS_DestroyAllUserSignals( + IN gckOS Os + ) +{ + gctINT signal; + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkVERIFY_OK(gckOS_AcquireMutex(Os, + Os->signal.lock, + gcvINFINITE + )); + + if (Os->signal.unused == Os->signal.tableLen) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + return gcvSTATUS_OK; + } + + for (signal = 0; signal < Os->signal.tableLen; signal++) + { + if (Os->signal.table[signal] != gcvNULL && + ((gcsSIGNAL_PTR)Os->signal.table[signal])->process == (gctHANDLE) current->tgid) + { + gckOS_Signal(Os, Os->signal.table[signal], gcvTRUE); + + gckOS_DestroySignal(Os, Os->signal.table[signal]); + + /* Update the signal table. */ + Os->signal.table[signal] = gcvNULL; + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = signal; + } + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + return gcvSTATUS_OK; +} + +#endif /* USE_NEW_LINUX_SIGNAL */ + +/******************************************************************************* +** +** gckOS_MapUserMemory +** +** Lock down a user buffer and return an DMA'able address to be used by the +** hardware to access it. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to lock down. +** +** gctSIZE_T Size +** Size in bytes of the memory to lock down. +** +** OUTPUT: +** +** gctPOINTER * Info +** Pointer to variable receiving the information record required by +** gckOS_UnmapUserMemory. +** +** gctUINT32_PTR Address +** Pointer to a variable that will receive the address DMA'able by the +** hardware. +*/ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ) +{ + gceSTATUS status; + gctSIZE_T pageCount, i, j; + gctUINT32_PTR pageTable; + gctUINT32 address; + gctUINT32 start, end, memory; + gctINT result = 0; + + gcsPageInfo_PTR info = gcvNULL; + struct page **pages = gcvNULL; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] enter." + ); + + do + { + memory = (gctUINT32) Memory; + + /* Get the number of required pages. */ + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] pageCount: %d.", + pageCount + ); + + /* Invalid argument. */ + if (pageCount == 0) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Overflow. */ + if ((memory + Size) < memory) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + MEMORY_MAP_LOCK(Os); + + /* Allocate the Info struct. */ + info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL); + + if (info == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Allocate the array of page addresses. */ + pages = (struct page **)kmalloc(pageCount * sizeof(struct page *), GFP_KERNEL); + + if (pages == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Get the user pages. */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, + current->mm, + memory & PAGE_MASK, + pageCount, + 1, + 0, + pages, + NULL + ); + up_read(¤t->mm->mmap_sem); + + if (result <=0 || result < pageCount) + { + struct vm_area_struct *vma; + + vma = find_vma(current->mm, memory); + + if (vma && (vma->vm_flags & VM_PFNMAP) ) + { + do + { + pte_t * pte; + spinlock_t * ptl; + unsigned long pfn; + + pgd_t * pgd = pgd_offset(current->mm, memory); + pud_t * pud = pud_offset(pgd, memory); + if (pud) + { + pmd_t * pmd = pmd_offset(pud, memory); + if (pmd) + { + pte = pte_offset_map_lock(current->mm, pmd, memory, &ptl); + if (!pte) + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + + pfn = pte_pfn(*pte); + *Address = ((pfn << PAGE_SHIFT) | (((unsigned long)Memory) & ~PAGE_MASK)) + - Os->baseAddress; + *Info = gcvNULL; + + pte_unmap_unlock(pte, ptl); + + /* Release page info struct. */ + if (info != gcvNULL) + { + /* Free the page info struct. */ + kfree(info); + } + + /* Free the page table. */ + if (pages != gcvNULL) + { + /* Release the pages if any. */ + if (result > 0) + { + for (i = 0; i < result; i++) + { + if (pages[i] == gcvNULL) + { + break; + } + + page_cache_release(pages[i]); + } + } + + kfree(pages); + } + + MEMORY_MAP_UNLOCK(Os); + + gcmkFOOTER_ARG("*Info=0x%x *Address=0x%08x", + *Info, *Address); + return gcvSTATUS_OK; + } + while (gcvFALSE); + + *Address = ~0; + *Info = gcvNULL; + + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + else + { + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + } + + for (i = 0; i < pageCount; i++) + { + /* Flush the data cache. */ +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_TO_DEVICE); +#else + flush_dcache_page(pages[i]); +#endif + } + + /* Allocate pages inside the page table. */ + gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernel->mmu, + pageCount * (PAGE_SIZE/4096), + (gctPOINTER *) &pageTable, + &address)); + + /* Fill the page table. */ + for (i = 0; i < pageCount; i++) + { + /* Get the physical address from page struct. */ + pageTable[i * (PAGE_SIZE/4096)] = page_to_phys(pages[i]); + + for (j = 1; j < (PAGE_SIZE/4096); j++) + { + pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] pages[%d]: 0x%x, pageTable[%d]: 0x%x.", + i, pages[i], + i, pageTable[i]); + } + + /* Save pointer to page table. */ + info->pageTable = pageTable; + info->pages = pages; + + *Info = (gctPOINTER) info; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] info->pages: 0x%x, info->pageTable: 0x%x, info: 0x%x.", + info->pages, + info->pageTable, + info + ); + + /* Return address. */ + *Address = address + (memory & ~PAGE_MASK); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_MapUserMemory] Address: 0x%x.", + *Address + ); + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error occured: %d.", + status + ); + + /* Release page array. */ + if (result > 0 && pages != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: page table is freed." + ); + + for (i = 0; i < result; i++) + { + if (pages[i] == gcvNULL) + { + break; + } +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_FROM_DEVICE); +#endif + page_cache_release(pages[i]); + } + } + + if (pages != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: pages is freed." + ); + + /* Free the page table. */ + kfree(pages); + info->pages = gcvNULL; + } + + /* Release page info struct. */ + if (info != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "[gckOS_MapUserMemory] error: info is freed." + ); + + /* Free the page info struct. */ + kfree(info); + *Info = gcvNULL; + } + } + + MEMORY_MAP_UNLOCK(Os); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_MapUserMemory] leave." + ); + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_UnmapUserMemory +** +** Unlock a user buffer and that was previously locked down by +** gckOS_MapUserMemory. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to unlock. +** +** gctSIZE_T Size +** Size in bytes of the memory to unlock. +** +** gctPOINTER Info +** Information record returned by gckOS_MapUserMemory. +** +** gctUINT32_PTR Address +** The address returned by gckOS_MapUserMemory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ) +{ + gceSTATUS status; + gctUINT32 memory, start, end; + gcsPageInfo_PTR info; + gctSIZE_T pageCount, i; + struct page **pages; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] enter." + ); + + do + { + info = (gcsPageInfo_PTR) Info; + + if (info == gcvNULL) + { + return gcvSTATUS_OK; + } + + pages = info->pages; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] info: 0x%x, pages: 0x%x.", + info, + pages + ); + + /* Invalid page array. */ + if (pages == gcvNULL) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + memory = (gctUINT32) Memory; + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + /* Overflow. */ + if ((memory + Size) < memory) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Invalid argument. */ + if (pageCount == 0) + { + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] memory: 0x%x, pageCount: %d, pageTable: 0x%x.", + memory, + pageCount, + info->pageTable + ); + + MEMORY_MAP_LOCK(Os); + + /* Free the pages from the MMU. */ + gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernel->mmu, + info->pageTable, + pageCount * (PAGE_SIZE/4096) + )); + + /* Release the page cache. */ + for (i = 0; i < pageCount; i++) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, + gcvZONE_OS, + "[gckOS_UnmapUserMemory] pages[%d]: 0x%x.", + i, + pages[i] + ); + + if (!PageReserved(pages[i])) + { + SetPageDirty(pages[i]); + } + +#ifdef ANDROID + dma_sync_single_for_device( + gcvNULL, + page_to_phys(pages[i]), + PAGE_SIZE, + DMA_FROM_DEVICE); +#endif + page_cache_release(pages[i]); + } + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + if (info != gcvNULL) + { + /* Free the page array. */ + if (info->pages != gcvNULL) + { + kfree(info->pages); + } + + kfree(info); + } + + MEMORY_MAP_UNLOCK(Os); + + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_GetBaseAddress +** +** Get the base address for the physical memory. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctUINT32_PTR BaseAddress +** Pointer to a variable that will receive the base address. +*/ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Return base address. */ + *BaseAddress = Os->baseAddress; + + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + disable_irq(Os->device->irqLine); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ) +{ + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + enable_irq(Os->device->irqLine); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ) +{ + gcmkVERIFY_ARGUMENT(Destination != NULL); + gcmkVERIFY_ARGUMENT(Source != NULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memcpy(Destination, Source, Bytes); + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Memory=0x%x Bytes=%lu", Memory, Bytes); + + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memset(Memory, 0, Bytes); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#if gcdkUSE_MEMORY_RECORD +MEMORY_RECORD_PTR +CreateMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gceMEMORY_TYPE Type, + gctSIZE_T Bytes, + gctPHYS_ADDR Physical, + gctPOINTER Logical + ) +{ + MEMORY_RECORD_PTR mr; + + gcmkASSERT(Type == gcvCONTIGUOUS_MEMORY || Type == gcvNON_PAGED_MEMORY); + + mr = (MEMORY_RECORD_PTR)kmalloc(sizeof(struct MEMORY_RECORD), GFP_ATOMIC); + if (mr == gcvNULL) return gcvNULL; + + MEMORY_LOCK(Os); + + mr->type = Type; + mr->u.Memory.bytes = Bytes; + mr->u.Memory.physical = Physical; + mr->u.Memory.logical = Logical; + + mr->prev = List->prev; + mr->next = List; + List->prev->next = mr; + List->prev = mr; + + MEMORY_UNLOCK(Os); + + return mr; +} + +void +DestroyMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR Mr + ) +{ + gcmkASSERT(Mr->type == gcvCONTIGUOUS_MEMORY || Mr->type == gcvNON_PAGED_MEMORY); + + MEMORY_LOCK(Os); + + Mr->prev->next = Mr->next; + Mr->next->prev = Mr->prev; + + MEMORY_UNLOCK(Os); + + kfree(Mr); +} + +MEMORY_RECORD_PTR +FindMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gceMEMORY_TYPE Type, + gctSIZE_T Bytes, + gctPHYS_ADDR Physical, + gctPOINTER Logical + ) +{ + MEMORY_RECORD_PTR mr; + + gcmkASSERT(Type == gcvCONTIGUOUS_MEMORY || Type == gcvNON_PAGED_MEMORY); + + MEMORY_LOCK(Os); + + mr = List->next; + + while (mr != List) + { + if (mr->type == Type + && mr->u.Memory.bytes == Bytes + && mr->u.Memory.physical == Physical + && mr->u.Memory.logical == Logical) + { + MEMORY_UNLOCK(Os); + + return mr; + } + + mr = mr->next; + } + + MEMORY_UNLOCK(Os); + + return gcvNULL; +} + +MEMORY_RECORD_PTR +CreateVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node, + gceSURF_TYPE Type, + gctSIZE_T Bytes + ) +{ + MEMORY_RECORD_PTR mr; + + mr = (MEMORY_RECORD_PTR)kmalloc(sizeof(struct MEMORY_RECORD), GFP_ATOMIC); + if (mr == gcvNULL) return gcvNULL; + + MEMORY_LOCK(Os); + + mr->type = gcvVIDEO_MEMORY; + mr->u.VideoMemory.node = Node; + mr->u.VideoMemory.type = Type; + mr->u.VideoMemory.bytes = Bytes; + +#if gcdkREPORT_VIDMEM_USAGE + private->allocatedMem[Type] += Bytes; + private->maxAllocatedMem[Type] = + (private->maxAllocatedMem[Type] > private->allocatedMem[Type]) + ? private->maxAllocatedMem[Type] : private->allocatedMem[Type]; + + private->totalAllocatedMem += Bytes; + private->maxTotalAllocatedMem = + (private->maxTotalAllocatedMem > private->totalAllocatedMem) + ? private->maxTotalAllocatedMem : private->totalAllocatedMem; +#endif + + mr->prev = List->prev; + mr->next = List; + List->prev->next = mr; + List->prev = mr; + + MEMORY_UNLOCK(Os); + + return mr; +} + +void +DestroyVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR Mr + ) +{ + gcmkASSERT(Mr->type == gcvVIDEO_MEMORY); + + MEMORY_LOCK(Os); + +#if gcdkREPORT_VIDMEM_USAGE + private->allocatedMem[Mr->u.VideoMemory.type] -= Mr->u.VideoMemory.bytes; + private->totalAllocatedMem -= Mr->u.VideoMemory.bytes; +#endif + + Mr->prev->next = Mr->next; + Mr->next->prev = Mr->prev; + + MEMORY_UNLOCK(Os); + + kfree(Mr); +} + +MEMORY_RECORD_PTR +FindVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ) +{ + MEMORY_RECORD_PTR mr; + + MEMORY_LOCK(Os); + + mr = List->next; + + while (mr != List) + { + if (mr->type == gcvVIDEO_MEMORY && mr->u.VideoMemory.node == Node) + { + MEMORY_UNLOCK(Os); + + return mr; + } + + mr = mr->next; + } + + MEMORY_UNLOCK(Os); + + return gcvNULL; +} + +void +FreeAllMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List + ) +{ + MEMORY_RECORD_PTR mr; + gctUINT i = 0; + +#if gcdkREPORT_VIDMEM_USAGE + gctUINT type; + + printk("------------------------------------\n"); + printk(" Type Current Max\n"); + + for (type = 0; type < gcvSURF_NUM_TYPES; type++) + { + printk("[%8s] %8llu KB %8llu KB\n", + _MemTypes[type], + private->allocatedMem[type] / 1024, + private->maxAllocatedMem[type] / 1024); + } + + printk("[ TOTAL] %8llu KB %8llu KB\n", + private->totalAllocatedMem / 1024, + private->maxTotalAllocatedMem / 1024); +#endif + + MEMORY_LOCK(Os); + + while (List->next != List) + { + mr = List->next; + + mr->prev->next = mr->next; + mr->next->prev = mr->prev; + + i++; + + MEMORY_UNLOCK(Os); + + switch (mr->type) + { + case gcvNON_PAGED_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Unfreed non-paged memory: physical: %p, logical: %p, bytes: %d", + mr->u.Memory.physical, mr->u.Memory.logical, mr->u.Memory.bytes); + + gckOS_FreeNonPagedMemory(Os, + mr->u.Memory.bytes, + mr->u.Memory.physical, + mr->u.Memory.logical); + break; + + case gcvCONTIGUOUS_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Unfreed contiguous memory: physical: %p, logical: %p, bytes: %d", + mr->u.Memory.physical, mr->u.Memory.logical, mr->u.Memory.bytes); + + gckOS_FreeContiguous(Os, + mr->u.Memory.physical, + mr->u.Memory.logical, + mr->u.Memory.bytes); + break; + + case gcvVIDEO_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "Unfreed %s memory: node: %p", + (mr->u.VideoMemory.node->VidMem.memory->object.type == gcvOBJ_VIDMEM)? + "video" : (mr->u.VideoMemory.node->Virtual.contiguous)? + "virtual-contiguous" : "virtual", + mr->u.VideoMemory.node); + + while (gcvTRUE) + { + if (mr->u.VideoMemory.node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (mr->u.VideoMemory.node->VidMem.locked == 0) break; + } + else + { + if (mr->u.VideoMemory.node->Virtual.locked == 0) break; + } + + gckVIDMEM_Unlock(mr->u.VideoMemory.node, gcvSURF_TYPE_UNKNOWN, gcvNULL); + } + + gckVIDMEM_Free(mr->u.VideoMemory.node); + break; + + default: + gcmkASSERT(0); + break; + } + + kfree(mr); + + MEMORY_LOCK(Os); + } + + MEMORY_UNLOCK(Os); + + if (i > 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, + gcvZONE_OS, + "======== Total %d unfreed memory block(s) ========", i); + } +} +#endif + +/******************************************************************************* +** gckOS_CacheFlush +** +** Flush the cache for the specified addresses. The GPU is going to need the +** data. If the system is allocating memory as non-cachable, this function can +** be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheFlush( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** gckOS_CacheInvalidate +** +** Flush the cache for the specified addresses and invalidate the lines as +** well. The GPU is going to need and modify the data. If the system is +** allocating memory as non-cachable, this function can be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctHANDLE Process +** Process handle Logical belongs to or gcvNULL if Logical belongs to +** the kernel. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheInvalidate( + IN gckOS Os, + IN gctHANDLE Process, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + return gcvSTATUS_OK; +} + +/******************************************************************************* +********************************* Broadcasting ********************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Broadcast +** +** System hook for broadcast events from the kernel driver. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gceBROADCAST Reason +** Reason for the broadcast. Can be one of the following values: +** +** gcvBROADCAST_GPU_IDLE +** Broadcasted when the kernel driver thinks the GPU might be +** idle. This can be used to handle power management. +** +** gcvBROADCAST_GPU_COMMIT +** Broadcasted when any client process commits a command +** buffer. This can be used to handle power management. +** +** gcvBROADCAST_GPU_STUCK +** Broadcasted when the kernel driver hits the timeout waiting +** for the GPU. +** +** gcvBROADCAST_FIRST_PROCESS +** First process is trying to connect to the kernel. +** +** gcvBROADCAST_LAST_PROCESS +** Last process has detached from the kernel. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ) +{ + gceSTATUS status; + gctUINT32 idle = 0, dma = 0, axi = 0, read0 = 0, read1 = 0, write = 0; + gctUINT32 debugState = 0, memoryDebug = 0; + gctUINT32 debugCmdLow = 0, debugCmdHi = 0; + gctUINT32 i, debugSignalsPe, debugSignalsMc; + + gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Reason=%d", Os, Hardware, Reason); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + switch (Reason) + { + case gcvBROADCAST_FIRST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached"); + break; + + case gcvBROADCAST_LAST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached"); + + /* Put GPU OFF. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_OFF_BROADCAST)); + break; + + case gcvBROADCAST_GPU_IDLE: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle."); + + /* Put GPU IDLE. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_IDLE_BROADCAST)); + break; + + case gcvBROADCAST_GPU_COMMIT: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived."); + + /* Put GPU ON. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_ON_BROADCAST)); + break; + + case gcvBROADCAST_GPU_STUCK: + gcmkONERROR(gckHARDWARE_GetIdle(Hardware, gcvFALSE, &idle)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x00C, &axi)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x664, &dma)); + gcmkPRINT("!!FATAL!! GPU Stuck"); + gcmkPRINT(" idle=0x%08X axi=0x%08X cmd=0x%08X", idle, axi, dma); + + if (Hardware->chipFeatures & (1 << 4)) + { + gcmkONERROR(gckOS_ReadRegister(Os, 0x43C, &read0)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x440, &read1)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x444, &write)); + gcmkPRINT(" read0=0x%08X read1=0x%08X write=0x%08X", + read0, read1, write); + } + + gcmkONERROR(gckOS_ReadRegister(Os, 0x660, &debugState)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x414, &memoryDebug)); + gcmkPRINT(" debugState(0x660)=0x%08X memoryDebug(0x414)=0x%08X", + debugState, memoryDebug); + + gcmkONERROR(gckOS_ReadRegister(Os, 0x668, &debugCmdLow)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x66C, &debugCmdHi)); + gcmkPRINT(" debugCmdLow(0x668)=0x%08X debugCmdHi(0x66C)=0x%08X", + debugCmdLow, debugCmdHi); + + for (i = 0; i < 16; i++) + { + gcmkONERROR(gckOS_WriteRegister(Os, 0x470, i << 16)); + gcmkPRINT("%d: Write 0x%08X to DebugControl0(0x470)", i, i << 16); + + gcmkONERROR(gckOS_ReadRegister(Os, 0x454, &debugSignalsPe)); + gcmkPRINT("%d: debugSignalsPe(0x454)=0x%08X", i, debugSignalsPe); + + gcmkPRINT(""); + } + + for (i = 0; i < 16; i++) + { + gcmkONERROR(gckOS_WriteRegister(Os, 0x478, i)); + gcmkPRINT("%d: Write 0x%08X to DebugControl2(0x478)", i, i); + + gcmkONERROR(gckOS_ReadRegister(Os, 0x468, &debugSignalsMc)); + gcmkPRINT("%d: debugSignalsMc(0x468)=0x%08X", i, debugSignalsMc); + + gcmkPRINT(""); + } + + + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + + case gcvBROADCAST_AXI_BUS_ERROR: + gcmkONERROR(gckHARDWARE_GetIdle(Hardware, gcvFALSE, &idle)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x00C, &axi)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x664, &dma)); + gcmkPRINT("!!FATAL!! AXI Bus Error"); + gcmkPRINT(" idle=0x%08X axi=0x%08X cmd=0x%08X", idle, axi, dma); + + if (Hardware->chipFeatures & (1 << 4)) + { + gcmkONERROR(gckOS_ReadRegister(Os, 0x43C, &read0)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x440, &read1)); + gcmkONERROR(gckOS_ReadRegister(Os, 0x444, &write)); + gcmkPRINT(" read0=0x%08X read1=0x%08X write=0x%08X", + read0, read1, write); + } + + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +********************************** Semaphores ********************************** +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_CreateSemaphore +** +** Create a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Semaphore +** Pointer to the variable that will receive the created semaphore. +*/ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ) +{ + gceSTATUS status; + struct semaphore *sem; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Allocate the semaphore structure. */ + gcmkONERROR( + gckOS_Allocate(Os, gcmSIZEOF(struct semaphore), (gctPOINTER *) &sem)); + + /* Initialize the semaphore. */ + sema_init(sem, 1); + + /* Return to caller. */ + *Semaphore = (gctPOINTER) sem; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AcquireSemaphore +** +** Acquire a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Acquire the semaphore. */ + if (down_interruptible((struct semaphore *) Semaphore)) + { + gcmkONERROR(gcvSTATUS_TIMEOUT); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_ReleaseSemaphore +** +** Release a previously acquired semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gcmkHEADER_ARG("Os=0x%x Semaphore=0x%x", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Release the semaphore. */ + up((struct semaphore *) Semaphore); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DestroySemaphore +** +** Destroy a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Semaphore=0x%x", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Free the sempahore structure. */ + gcmkONERROR(gckOS_Free(Os, Semaphore)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ) +{ + gcmkHEADER(); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(ProcessID != gcvNULL); + + /* Get process ID. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + *ProcessID = task_tgid_vnr(current); +#else + *ProcessID = current->tgid; +#endif + + /* Success. */ + gcmkFOOTER_ARG("*ProcessID=%u", *ProcessID); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ) +{ + gcmkHEADER(); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(ThreadID != gcvNULL); + + /* Get thread ID. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + *ThreadID = task_pid_vnr(current); +#else + *ThreadID = current->pid; +#endif + + /* Success. */ + gcmkFOOTER_ARG("*ThreadID=%u", *ThreadID); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ) +{ + gcmkHEADER_ARG("Os=0x%x Clock=%d Power=%d", Os, Clock, Power); + + /* TODO: Put your code here. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + diff --git a/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.h b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.h new file mode 100644 index 0000000..172ec91 --- /dev/null +++ b/kernel_drivers/v2/hal/os/linux/kernel/gc_hal_kernel_os.h @@ -0,0 +1,140 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_os_h_ +#define __gc_hal_kernel_os_h_ + +typedef struct _LINUX_MDL_MAP +{ + gctINT pid; + gctPOINTER vmaAddr; + struct vm_area_struct * vma; + struct _LINUX_MDL_MAP * next; +} +LINUX_MDL_MAP, *PLINUX_MDL_MAP; + +typedef struct _LINUX_MDL +{ + gctINT pid; + char * addr; + +#ifdef NO_DMA_COHERENT + gctPOINTER kaddr; +#endif /* NO_DMA_COHERENT */ + + gctINT numPages; + gctINT pagedMem; + gctBOOL contiguous; + dma_addr_t dmaHandle; + PLINUX_MDL_MAP maps; + struct _LINUX_MDL * prev; + struct _LINUX_MDL * next; +} +LINUX_MDL, *PLINUX_MDL; + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ); + +typedef struct _DRIVER_ARGS +{ + gctPOINTER InputBuffer; + gctUINT32 InputBufferSize; + gctPOINTER OutputBuffer; + gctUINT32 OutputBufferSize; +} +DRIVER_ARGS; + +/* Destroy all user signals of the current process */ +gceSTATUS +gckOS_DestroyAllUserSignals( + IN gckOS Os + ); + +#ifdef gcdkUSE_MEMORY_RECORD +MEMORY_RECORD_PTR +CreateMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gceMEMORY_TYPE Type, + gctSIZE_T Bytes, + gctPHYS_ADDR Physical, + gctPOINTER Logical + ); + +void +DestroyMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR Mr + ); + +MEMORY_RECORD_PTR +FindMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gceMEMORY_TYPE Type, + gctSIZE_T Bytes, + gctPHYS_ADDR Physical, + gctPOINTER Logical + ); + +MEMORY_RECORD_PTR +CreateVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node, + gceSURF_TYPE Type, + gctSIZE_T Bytes + ); + +void +DestroyVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR Mr + ); + +MEMORY_RECORD_PTR +FindVideoMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List, + gcuVIDMEM_NODE_PTR Node + ); + +void +FreeAllMemoryRecord( + gckOS Os, + gcsHAL_PRIVATE_DATA_PTR private, + MEMORY_RECORD_PTR List + ); +#endif + +#endif /* __gc_hal_kernel_os_h_ */ + diff --git a/kernel_drivers/v2/hal/user/gc_hal_user_context.h b/kernel_drivers/v2/hal/user/gc_hal_user_context.h new file mode 100644 index 0000000..abc1481 --- /dev/null +++ b/kernel_drivers/v2/hal/user/gc_hal_user_context.h @@ -0,0 +1,170 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2011 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_user_context_h_ +#define __gc_hal_user_context_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* gcoCONTEXT structure that hold the current context. */ +struct _gcoCONTEXT +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to gcoHARDWARE object. */ + gcoHARDWARE hardware; + + /* Context ID. */ + gctUINT64 id; + + /* State mapping. */ + gctUINT32_PTR map; + gctSIZE_T stateCount; + + /* State hinting. */ + gctUINT8_PTR hint; + gctUINT8 hintValue; + gctSIZE_T hintCount; + + /* Context buffer. */ + gctUINT32_PTR buffer; + gctUINT32 pipe3DIndex; + gctUINT32 pipe2DIndex; + gctUINT32 linkIndex; + gctUINT32 inUseIndex; + gctSIZE_T bufferSize; + + /* Context buffer used for commitment. */ + gctSIZE_T bytes; + gctPHYS_ADDR physical; + gctPOINTER logical; + + /* Pointer to final LINK command. */ + gctPOINTER link; + + /* Requested pipe select for context. */ + gctUINT32 initialPipe; + gctUINT32 entryPipe; + gctUINT32 currentPipe; + + /* Flag to specify whether PostCommit needs to be called. */ + gctBOOL postCommit; + + /* Busy flag. */ + volatile gctBOOL * inUse; + + /* Variables used for building state buffer. */ + gctUINT32 lastAddress; + gctSIZE_T lastSize; + gctUINT32 lastIndex; + gctBOOL lastFixed; + + /* Hint array. */ + gctUINT32_PTR hintArray; + gctUINT32_PTR hintIndex; +}; + +struct _gcoCMDBUF +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to gcoHARDWARE object. */ + gcoHARDWARE hardware; + + /* Physical address of command buffer. */ + gctPHYS_ADDR physical; + + /* Logical address of command buffer. */ + gctPOINTER logical; + + /* Number of bytes in command buffer. */ + gctSIZE_T bytes; + + /* Start offset into the command buffer. */ + gctUINT32 startOffset; + + /* Current offset into the command buffer. */ + gctUINT32 offset; + + /* Number of free bytes in command buffer. */ + gctSIZE_T free; + +#if gcdSECURE_USER + /* Table of offsets that define the physical addresses to be mapped. */ + gctUINT32_PTR hintTable; + + /* Current index into map table. */ + gctUINT32_PTR hintIndex; + + /* Commit index for map table. */ + gctUINT32_PTR hintCommit; +#endif +}; + +typedef struct _gcsQUEUE * gcsQUEUE_PTR; + +typedef struct _gcsQUEUE +{ + /* Pointer to next gcsQUEUE structure. */ + gcsQUEUE_PTR next; + +#ifdef __QNXNTO__ + /* Size of this object. */ + gctSIZE_T bytes; +#endif + + /* Event information. */ + gcsHAL_INTERFACE iface; +} +gcsQUEUE; + +/* Event queue. */ +struct _gcoQUEUE +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gcoOS object. */ + gcoOS os; + + /* Pointer to current event queue. */ + gcsQUEUE_PTR head; + gcsQUEUE_PTR tail; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_user_context_h_ */ + diff --git a/kernel_drivers/v4/Kconfig b/kernel_drivers/v4/Kconfig new file mode 100644 index 0000000..f830f42 --- /dev/null +++ b/kernel_drivers/v4/Kconfig @@ -0,0 +1,28 @@ +if GPU_VIVANTE_V4 + +menu "Vivante Options" + +config GPU_VIVANTE_ANDROID + bool + default y if ANDROID + default n + +config GPU_VIVANTE_DEBUG + boolean "Enable debug output" + +config GPU_VIVANTE_PROFILER + boolean "Enable profiler" + +config GPU_VIVANTE_NEWSIGNAL + boolean "Use new linux signal" + +config GPU_VIVANTE_NO_DMA_COHERENT + boolean "Disable coherent DMA function" + +config GPU_VIVANTE_POWER_MANAGEMENT + boolean "Enable power management" + default y + +endmenu + +endif diff --git a/kernel_drivers/v4/Makefile b/kernel_drivers/v4/Makefile new file mode 100644 index 0000000..2ce86e7 --- /dev/null +++ b/kernel_drivers/v4/Makefile @@ -0,0 +1,104 @@ +# +# Makefile for Vivante GPU driver + +debug = 0 +profiler = 0 +newsignal = 0 +pm = 0 + +bank_bit_start = 0 +bank_bit_end = 0 +bank_channel_bit = 0 + +ifeq ($(CONFIG_GPU_VIVANTE_DEBUG),y) + debug = 1 +endif + +ifeq ($(CONFIG_GPU_VIVANTE_PROFILER),y) + profiler = 1 +endif + +ifeq ($(CONFIG_GPU_VIVANTE_NEWSIGNAL),y) + newsignal = 1 +endif + +ifeq ($(CONFIG_GPU_VIVANTE_POWER_MANAGEMENT),y) + pm = 1 +endif + +ccflags-y += -DENUM_WORKAROUND=0 + +ccflags-y += -DDBG=$(debug) +ccflags-$(CONFIG_GPU_VIVANTE_DEBUG) += -DDEBUG -D_DEBUG + +ifeq ($(CONFIG_GPU_VIVANTE_NO_DMA_COHERENT),y) + ccflags-y += -DNO_DMA_COHERENT +endif + +ccflags-y += -DgcdPOWER_MANAGEMENT=$(pm) +ccflags-y += -DUSE_PLATFORM_DRIVER=1 +ccflags-y += -DVIVANTE_PROFILER=$(profiler) + +ifeq ($(CONFIG_GPU_VIVANTE_ANDROID),y) + ccflags-y += -DANDROID=1 +endif + +ccflags-y += -DUSE_NEW_LINUX_SIGNAL=$(newsignal) +ccflags-y += -DNO_USER_DIRECT_ACCESS_FROM_KERNEL=1 +ccflags-y += -DgcdPAGED_MEMORY_CACHEABLE=0 +ccflags-y += -DgcdNONPAGED_MEMORY_CACHEABLE=0 +ccflags-y += -DgcdNONPAGED_MEMORY_BUFFERABLE=1 +ccflags-y += -DgcdCACHE_FUNCTION_UNIMPLEMENTED=0 +ccflags-y += -DgcdENABLE_VG=0 +ccflags-y += -DgcdSUPPORT_SWAP_RECTANGLE=0 +ccflags-y += -DgcdENABLE_OUTER_CACHE_PATCH=0 +ccflags-y += -DgcdUSE_OPENCL=0 + +ifeq ($(CONFIG_SMP), y) + ccflags-y += -DgcdSMP=1 +else + ccflags-y += -DgcdSMP=0 +endif + + +ifeq ($(CONFIG_GPU_VIVANTE_USE_BANK_ALIGNMENT), y) + ccflags-y += -DgcdENABLE_BANK_ALIGNMENT=1 + ifneq ($(bank_bit_start), 0) + ifneq ($(bank_bit_end), 0) + ccflags-y += -DgcdBANK_BIT_START=$(bank_bit_start) + ccflags-y += -DgcdBANK_BIT_END=$(bank_bit_end) + endif + endif + + ifneq ($(bank_channel_bit), 0) + ccflags-y += -DgcdBANK_CHANNEL_BIT=$(bank_channel_bit) + endif +endif + + +# setup includes +ccflags-y += \ + -I$(obj)/hal/user \ + -I$(obj)/hal/kernel \ + -I$(obj)/hal/kernel/inc \ + -I$(obj)/hal/os/linux/kernel \ + -I$(obj)/arch/XAQ2/hal/kernel + +obj-$(CONFIG_GPU_VIVANTE_V4) += galcore.o + +galcore-objs += \ + hal/kernel/gc_hal_kernel.o \ + hal/kernel/gc_hal_kernel_command.o \ + hal/kernel/gc_hal_kernel_db.o \ + hal/kernel/gc_hal_kernel_debug.o \ + hal/kernel/gc_hal_kernel_event.o \ + hal/kernel/gc_hal_kernel_heap.o \ + hal/kernel/gc_hal_kernel_mmu.o \ + hal/kernel/gc_hal_kernel_video_memory.o \ + hal/os/linux/kernel/gc_hal_kernel_device.o \ + hal/os/linux/kernel/gc_hal_kernel_driver.o \ + hal/os/linux/kernel/gc_hal_kernel_linux.o \ + hal/os/linux/kernel/gc_hal_kernel_math.o \ + hal/os/linux/kernel/gc_hal_kernel_os.o \ + arch/XAQ2/hal/kernel/gc_hal_kernel_context.o \ + arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.o diff --git a/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.c b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.c new file mode 100644 index 0000000..1e25ecd --- /dev/null +++ b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.c @@ -0,0 +1,1693 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + + + +#include "gc_hal.h" +#include "gc_hal_kernel.h" +#include "gc_hal_kernel_context.h" +#include "gc_hal_kernel_buffer.h" + +/******************************************************************************\ +******************************** Debugging Macro ******************************* +\******************************************************************************/ + +/* Zone used for header/footer. */ +#define _GC_OBJ_ZONE gcvZONE_HARDWARE + + +/******************************************************************************\ +************************** Context State Buffer Helpers ************************ +\******************************************************************************/ + +#define _STATE(reg) \ + _State(\ + Context, index, \ + reg ## _Address >> 2, \ + reg ## _ResetValue, \ + reg ## _Count, \ + gcvFALSE, gcvFALSE \ + ) + +#define _STATE_COUNT(reg, count) \ + _State(\ + Context, index, \ + reg ## _Address >> 2, \ + reg ## _ResetValue, \ + count, \ + gcvFALSE, gcvFALSE \ + ) + +#define _STATE_COUNT_OFFSET(reg, offset, count) \ + _State(\ + Context, index, \ + (reg ## _Address >> 2) + offset, \ + reg ## _ResetValue, \ + count, \ + gcvFALSE, gcvFALSE \ + ) + +#define _STATE_MIRROR_COUNT(reg, mirror, count) \ + _StateMirror(\ + Context, \ + reg ## _Address >> 2, \ + count, \ + mirror ## _Address >> 2 \ + ) + +#define _STATE_HINT(reg) \ + _State(\ + Context, index, \ + reg ## _Address >> 2, \ + reg ## _ResetValue, \ + reg ## _Count, \ + gcvFALSE, gcvTRUE \ + ) + +#define _STATE_HINT_BLOCK(reg, block, count) \ + _State(\ + Context, index, \ + (reg ## _Address >> 2) + (block << reg ## _BLK), \ + reg ## _ResetValue, \ + count, \ + gcvFALSE, gcvTRUE \ + ) + +#define _STATE_X(reg) \ + _State(\ + Context, index, \ + reg ## _Address >> 2, \ + reg ## _ResetValue, \ + reg ## _Count, \ + gcvTRUE, gcvFALSE \ + ) + +#define _CLOSE_RANGE() \ + _TerminateStateBlock(Context, index) + +#define _ENABLE(reg, field) \ + do \ + { \ + if (gcmVERIFYFIELDVALUE(data, reg, MASK_ ## field, ENABLED)) \ + { \ + enable |= gcmFIELDMASK(reg, field); \ + } \ + } \ + while (gcvFALSE) + +#define _BLOCK_COUNT(reg) \ + ((reg ## _Count) >> (reg ## _BLK)) + + +/******************************************************************************\ +*********************** Support Functions and Definitions ********************** +\******************************************************************************/ + +#define gcdSTATE_MASK \ + (((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 | 0xC0FFEE & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27)))) + +#if !defined(VIVANTE_NO_3D) +static gctSIZE_T +_TerminateStateBlock( + IN gckCONTEXT Context, + IN gctSIZE_T Index + ) +{ + gctUINT32_PTR buffer; + gctSIZE_T align; + + /* Determine if we need alignment. */ + align = (Index & 1) ? 1 : 0; + + /* Address correct index. */ + buffer = (Context->buffer == gcvNULL) + ? gcvNULL + : Context->buffer->logical; + + /* Flush the current state block; make sure no pairing with the states + to follow happens. */ + if (align && (buffer != gcvNULL)) + { + buffer[Index] = 0xDEADDEAD; + } + + /* Reset last address. */ + Context->lastAddress = ~0U; + + /* Return alignment requirement. */ + return align; +} +#endif + + +static gctSIZE_T +_FlushPipe( + IN gckCONTEXT Context, + IN gctSIZE_T Index, + IN gcePIPE_SELECT Pipe + ) +{ + if (Context->buffer != gcvNULL) + { + gctUINT32_PTR buffer; + + /* Address correct index. */ + buffer = Context->buffer->logical + Index; + + /* Flush the current pipe. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + *buffer++ + = (Pipe == gcvPIPE_2D) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) + : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); + + /* Semaphore from FE to PE. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* Stall from FE to PE. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + *buffer + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + } + + /* Flushing 3D pipe takes 6 slots. */ + return 6; +} + +static gctSIZE_T +_SemaphoreStall( + IN gckCONTEXT Context, + IN gctSIZE_T Index + ) +{ + if (Context->buffer != gcvNULL) + { + gctUINT32_PTR buffer; + + /* Address correct index. */ + buffer = Context->buffer->logical + Index; + + /* Semaphore from FE to PE. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* Stall from FE to PE. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + *buffer + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + } + + /* Semaphore/stall takes 4 slots. */ + return 4; +} + +static gctSIZE_T +_SwitchPipe( + IN gckCONTEXT Context, + IN gctSIZE_T Index, + IN gcePIPE_SELECT Pipe + ) +{ + if (Context->buffer != gcvNULL) + { + gctUINT32_PTR buffer; + + /* Address correct index. */ + buffer = Context->buffer->logical + Index; + + /* LoadState(AQPipeSelect, 1), pipe. */ + *buffer++ + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + *buffer + = (Pipe == gcvPIPE_2D) + ? 0x1 + : 0x0; + } + + return 2; +} + +#if !defined(VIVANTE_NO_3D) +static gctSIZE_T +_State( + IN gckCONTEXT Context, + IN gctSIZE_T Index, + IN gctUINT32 Address, + IN gctUINT32 Value, + IN gctSIZE_T Size, + IN gctBOOL FixedPoint, + IN gctBOOL Hinted + ) +{ + gctUINT32_PTR buffer; + gctSIZE_T align, i; + + /* Determine if we need alignment. */ + align = (Index & 1) ? 1 : 0; + + /* Address correct index. */ + buffer = (Context->buffer == gcvNULL) + ? gcvNULL + : Context->buffer->logical; + + if ((buffer == gcvNULL) && (Address + Size > Context->stateCount)) + { + /* Determine maximum state. */ + Context->stateCount = Address + Size; + } + + /* Do we need a new entry? */ + if ((Address != Context->lastAddress) || (FixedPoint != Context->lastFixed)) + { + if (buffer != gcvNULL) + { + if (align) + { + /* Add filler. */ + buffer[Index++] = 0xDEADDEAD; + } + + /* LoadState(Address, Count). */ + gcmkASSERT((Index & 1) == 0); + + if (FixedPoint) + { + buffer[Index] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + } + else + { + buffer[Index] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 26:26) - (0 ? 26:26) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 26:26) - (0 ? 26:26) + 1))))))) << (0 ? 26:26))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Address) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + } + + /* Walk all the states. */ + for (i = 0; i < Size; i += 1) + { + /* Set state to uninitialized value. */ + buffer[Index + 1 + i] = Value; + + /* Set index in state mapping table. */ + Context->map[Address + i].index = Index + 1 + i; + +#if gcdSECURE_USER + /* Save hint. */ + if (Context->hint != gcvNULL) + { + Context->hint[Address + i] = Hinted; + } +#endif + } + } + + /* Save information for this LoadState. */ + Context->lastIndex = Index; + Context->lastAddress = Address + Size; + Context->lastSize = Size; + Context->lastFixed = FixedPoint; + + /* Return size for load state. */ + return align + 1 + Size; + } + + /* Append this state to the previous one. */ + if (buffer != gcvNULL) + { + /* Update last load state. */ + buffer[Context->lastIndex] = + ((((gctUINT32) (buffer[Context->lastIndex])) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (Context->lastSize + Size) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + /* Walk all the states. */ + for (i = 0; i < Size; i += 1) + { + /* Set state to uninitialized value. */ + buffer[Index + i] = Value; + + /* Set index in state mapping table. */ + Context->map[Address + i].index = Index + i; + +#if gcdSECURE_USER + /* Save hint. */ + if (Context->hint != gcvNULL) + { + Context->hint[Address + i] = Hinted; + } +#endif + } + } + + /* Update last address and size. */ + Context->lastAddress += Size; + Context->lastSize += Size; + + /* Return number of slots required. */ + return Size; +} + +static gctSIZE_T +_StateMirror( + IN gckCONTEXT Context, + IN gctUINT32 Address, + IN gctSIZE_T Size, + IN gctUINT32 AddressMirror + ) +{ + gctSIZE_T i; + + /* Process when buffer is set. */ + if (Context->buffer != gcvNULL) + { + /* Walk all states. */ + for (i = 0; i < Size; i++) + { + /* Copy the mapping address. */ + Context->map[Address + i].index = + Context->map[AddressMirror + i].index; + } + } + + /* Return the number of required maps. */ + return Size; +} +#endif + +static gceSTATUS +_InitializeContextBuffer( + IN gckCONTEXT Context + ) +{ + gctUINT32_PTR buffer; + gctSIZE_T index; + +#if !defined(VIVANTE_NO_3D) + gctUINT i; + gctUINT vertexUniforms, fragmentUniforms; + gctUINT fe2vsCount; +#endif + + /* Reset the buffer index. */ + index = 0; + + /* Reset the last state address. */ + Context->lastAddress = ~0U; + + /* Get the buffer pointer. */ + buffer = (Context->buffer == gcvNULL) + ? gcvNULL + : Context->buffer->logical; + + + /**************************************************************************/ + /* Build 2D states. *******************************************************/ + + +#if !defined(VIVANTE_NO_3D) + /**************************************************************************/ + /* Build 3D states. *******************************************************/ + + /* Query shader support. */ + gcmkVERIFY_OK(gckHARDWARE_QueryShaderCaps( + Context->hardware, &vertexUniforms, &fragmentUniforms, gcvNULL)); + + /* Store the 3D entry index. */ + Context->entryOffset3D = index * gcmSIZEOF(gctUINT32); + + /* Flush 2D pipe. */ + index += _FlushPipe(Context, index, gcvPIPE_2D); + + /* Switch to 3D pipe. */ + index += _SwitchPipe(Context, index, gcvPIPE_3D); + + /* Current context pointer. */ +#if gcdDEBUG && 1 + index += _State(Context, index, 0x03850 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); +#endif + + /* Global states. */ + index += _State(Context, index, 0x03814 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x03818 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0381C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x03820 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x03828 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0382C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x03834 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x03838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0384C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + + /* Front End states. */ + fe2vsCount = 12; + if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures1)) >> (0 ? 23:23)) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) )) + { + fe2vsCount = 16; + } + index += _State(Context, index, 0x00600 >> 2, 0x00000000, fe2vsCount, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + index += _State(Context, index, 0x00644 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x00648 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0064C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x00650 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00680 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x006A0 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0067C >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x006C0 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00700 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00740 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00780 >> 2, 0x3F800000, 16, gcvFALSE, gcvFALSE); + + /* Vertex Shader states. */ + index += _State(Context, index, 0x00800 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00804 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00808 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0080C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00810 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00820 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00830 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00838 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + if (Context->hardware->identity.instructionCount <= 256) + { + index += _State(Context, index, 0x04000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE); + } + + index += _CLOSE_RANGE(); + index += _State(Context, index, 0x05000 >> 2, 0x00000000, vertexUniforms * 4, gcvFALSE, gcvFALSE); + + /* Primitive Assembly states. */ + index += _State(Context, index, 0x00A00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00A04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00A08 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A0C >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00A10 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00A14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A1C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A28 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A2C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A30 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A40 >> 2, 0x00000000, 10, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A34 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A38 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A3C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A80 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00A84 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + + /* Setup states. */ + index += _State(Context, index, 0x00C00 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00C04 >> 2, 0x00000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00C08 >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00C0C >> 2, 0x45000000, 1, gcvTRUE, gcvFALSE); + index += _State(Context, index, 0x00C10 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00C14 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00C18 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00C1C >> 2, 0x42000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00C20 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00C24 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + + /* Raster states. */ + index += _State(Context, index, 0x00E00 >> 2, 0x00000001, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00E10 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00E04 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00E40 >> 2, 0x00000000, 16, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00E08 >> 2, 0x00000031, 1, gcvFALSE, gcvFALSE); + + /* Pixel Shader states. */ + index += _State(Context, index, 0x01000 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01004 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0100C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01010 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01018 >> 2, 0x01000000, 1, gcvFALSE, gcvFALSE); + if (Context->hardware->identity.instructionCount <= 256) + { + index += _State(Context, index, 0x06000 >> 2, 0x00000000, 1024, gcvFALSE, gcvFALSE); + } + + index += _CLOSE_RANGE(); + index += _State(Context, index, 0x07000 >> 2, 0x00000000, fragmentUniforms * 4, gcvFALSE, gcvFALSE); + + /* Texture states. */ + index += _State(Context, index, 0x02000 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02040 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02080 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x020C0 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02100 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02140 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02180 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x021C0 >> 2, 0x00321000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02200 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x02240 >> 2, 0x00000000, 12, gcvFALSE, gcvFALSE); + index += _State(Context, index, (0x02400 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02440 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02480 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x024C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02500 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02540 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02580 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x025C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02600 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02640 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02680 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x026C0 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02700 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _State(Context, index, (0x02740 >> 2) + (0 << 4), 0x00000000, 12, gcvFALSE, gcvTRUE); + index += _CLOSE_RANGE(); + + if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures2)) >> (0 ? 11:11)) & ((gctUINT32) ((((1 ? 11:11) - (0 ? 11:11) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:11) - (0 ? 11:11) + 1)))))) )) + { + gctUINT texBlockCount; + + /* New texture block. */ + index += _State(Context, index, 0x10000 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10080 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10100 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10180 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10200 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10280 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10300 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10380 >> 2, 0x00321000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10400 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x10480 >> 2, 0x00000000, 32, gcvFALSE, gcvFALSE); + + if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures2)) >> (0 ? 15:15)) & ((gctUINT32) ((((1 ? 15:15) - (0 ? 15:15) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:15) - (0 ? 15:15) + 1)))))) )) + { + index += _State(Context, index, 0x12000 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x12400 >> 2, 0x00000000, 256, gcvFALSE, gcvFALSE); + } + + if ((Context->hardware->identity.chipModel == gcv2000) + && (Context->hardware->identity.chipRevision == 0x5108)) + { + texBlockCount = 12; + } + else + { + texBlockCount = ((512) >> (4)); + } + for (i = 0; i < texBlockCount; i += 1) + { + index += _State(Context, index, (0x10800 >> 2) + (i << 4), 0x00000000, 14, gcvFALSE, gcvTRUE); + } + } + + /* YUV. */ + index += _State(Context, index, 0x01678 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0167C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01680 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01684 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01688 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0168C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01690 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01694 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01698 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0169C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + /* Thread walker states. */ + index += _State(Context, index, 0x00900 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00904 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00908 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0090C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00910 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00914 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00918 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0091C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00924 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + if (Context->hardware->identity.instructionCount > 1024) + { + /* New Shader instruction memory. */ + index += _State(Context, index, 0x0085C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0101C >> 2, 0x00000100, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x00860 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + for (i = 0; + i < Context->hardware->identity.instructionCount << 2; + i += 256 << 2 + ) + { + index += _State(Context, index, (0x20000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + } + } + else if (Context->hardware->identity.instructionCount > 256) + { + /* VX instruction memory. */ + for (i = 0; + i < Context->hardware->identity.instructionCount << 2; + i += 256 << 2 + ) + { + index += _State(Context, index, (0x0C000 >> 2) + i, 0x00000000, 256 << 2, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + } + + _StateMirror(Context, 0x08000 >> 2, Context->hardware->identity.instructionCount << 2 , 0x0C000 >> 2); + } + + /* Store the index of the "XD" entry. */ + Context->entryOffsetXDFrom3D = index * gcmSIZEOF(gctUINT32); + + index += _FlushPipe(Context, index, gcvPIPE_3D); + + /* Pixel Engine states. */ + index += _State(Context, index, 0x01400 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01404 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01408 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0140C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01414 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01418 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0141C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01420 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01424 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01428 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0142C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01434 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01454 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01458 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0145C >> 2, 0x00000010, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014A8 >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014AC >> 2, 0xFFFFFFFF, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014B0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x014A4 >> 2, 0x000E400C, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01580 >> 2, 0x00000000, 3, gcvFALSE, gcvFALSE); + + /* Composition states. */ + index += _State(Context, index, 0x03008 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + + if (Context->hardware->identity.pixelPipes == 1) + { + index += _State(Context, index, 0x01430 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01410 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + } + else + { + index += _State(Context, index, (0x01460 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); + + index += _State(Context, index, (0x01480 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); + + for (i = 0; i < 2; i++) + { + index += _State(Context, index, (0x01500 >> 2) + (i << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); + } + } + + /* Resolve states. */ + index += _State(Context, index, 0x01604 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01608 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0160C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01610 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01614 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01620 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01630 >> 2, 0x00000000, 2, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01640 >> 2, 0x00000000, 4, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x0163C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x016A0 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x016B4 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + if (Context->hardware->identity.pixelPipes > 1) + { + index += _State(Context, index, (0x016C0 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); + + index += _State(Context, index, (0x016E0 >> 2) + (0 << 3), 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvTRUE); + + index += _State(Context, index, 0x01700 >> 2, 0x00000000, Context->hardware->identity.pixelPipes, gcvFALSE, gcvFALSE); + } + + /* Tile status. */ + index += _State(Context, index, 0x01654 >> 2, 0x00200000, 1, gcvFALSE, gcvFALSE); + + index += _CLOSE_RANGE(); + index += _State(Context, index, 0x01658 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0165C >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01660 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01664 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01668 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x0166C >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01670 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01674 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x016A4 >> 2, 0x00000000, 1, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x016A8 >> 2, 0x00000000, 1, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01720 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); + index += _State(Context, index, 0x01740 >> 2, 0x00000000, 8, gcvFALSE, gcvTRUE); + index += _State(Context, index, 0x01760 >> 2, 0x00000000, 8, gcvFALSE, gcvFALSE); + index += _CLOSE_RANGE(); + + /* Semaphore/stall. */ + index += _SemaphoreStall(Context, index); +#endif + + /**************************************************************************/ + /* Link to another address. ***********************************************/ + + Context->linkIndex3D = index; + + if (buffer != gcvNULL) + { + buffer[index + 0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[index + 1] + = 0; + } + + index += 2; + + /* Store the end of the context buffer. */ + Context->bufferSize = index * gcmSIZEOF(gctUINT32); + + + /**************************************************************************/ + /* Pipe switch for the case where neither 2D nor 3D are used. *************/ + + /* Store the 3D entry index. */ + Context->entryOffsetXDFrom2D = index * gcmSIZEOF(gctUINT32); + + /* Flush 2D pipe. */ + index += _FlushPipe(Context, index, gcvPIPE_2D); + + /* Switch to 3D pipe. */ + index += _SwitchPipe(Context, index, gcvPIPE_3D); + + /* Store the location of the link. */ + Context->linkIndexXD = index; + + if (buffer != gcvNULL) + { + buffer[index + 0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[index + 1] + = 0; + } + + index += 2; + + + /**************************************************************************/ + /* Save size for buffer. **************************************************/ + + Context->totalSize = index * gcmSIZEOF(gctUINT32); + + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_DestroyContext( + IN gckCONTEXT Context + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + if (Context != gcvNULL) + { + gcsCONTEXT_PTR bufferHead; + + /* Free context buffers. */ + for (bufferHead = Context->buffer; Context->buffer != gcvNULL;) + { + /* Get a shortcut to the current buffer. */ + gcsCONTEXT_PTR buffer = Context->buffer; + + /* Get the next buffer. */ + gcsCONTEXT_PTR next = buffer->next; + + /* Last item? */ + if (next == bufferHead) + { + next = gcvNULL; + } + + /* Destroy the signal. */ + if (buffer->signal != gcvNULL) + { + gcmkONERROR(gckOS_DestroySignal( + Context->os, buffer->signal + )); + + buffer->signal = gcvNULL; + } + + /* Free state delta map. */ + if (buffer->logical != gcvNULL) + { + gcmkONERROR(gckOS_FreeContiguous( + Context->os, + buffer->physical, + buffer->logical, + Context->totalSize + )); + + buffer->logical = gcvNULL; + } + + /* Free context buffer. */ + gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, buffer)); + + /* Remove from the list. */ + Context->buffer = next; + } + +#if gcdSECURE_USER + /* Free the hint array. */ + if (Context->hint != gcvNULL) + { + gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->hint)); + } +#endif + /* Free record array copy. */ + if (Context->recordArray != gcvNULL) + { + gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->recordArray)); + } + + /* Free the state mapping. */ + if (Context->map != gcvNULL) + { + gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context->map)); + } + + /* Mark the gckCONTEXT object as unknown. */ + Context->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckCONTEXT object. */ + gcmkONERROR(gcmkOS_SAFE_FREE(Context->os, Context)); + } + +OnError: + return status; +} + + +/******************************************************************************\ +**************************** Context Management API **************************** +\******************************************************************************/ + +/******************************************************************************\ +** +** gckCONTEXT_Construct +** +** Construct a new gckCONTEXT object. +** +** INPUT: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctUINT32 ProcessID +** Current process ID. +** +** gckHARDWARE Hardware +** Pointer to gckHARDWARE object. +** +** OUTPUT: +** +** gckCONTEXT * Context +** Pointer to a variable thet will receive the gckCONTEXT object +** pointer. +*/ +gceSTATUS +gckCONTEXT_Construct( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT32 ProcessID, + OUT gckCONTEXT * Context + ) +{ + gceSTATUS status; + gckCONTEXT context = gcvNULL; + gctSIZE_T allocationSize; + gctUINT i; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Os=0x%08X Hardware=0x%08X", Os, Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Context != gcvNULL); + + + /**************************************************************************/ + /* Allocate and initialize basic fields of gckCONTEXT. ********************/ + + /* The context object size. */ + allocationSize = gcmSIZEOF(struct _gckCONTEXT); + + /* Allocate the object. */ + gcmkONERROR(gckOS_Allocate( + Os, allocationSize, &pointer + )); + + context = pointer; + + /* Reset the entire object. */ + gcmkONERROR(gckOS_ZeroMemory(context, allocationSize)); + + /* Initialize the gckCONTEXT object. */ + context->object.type = gcvOBJ_CONTEXT; + context->os = Os; + context->hardware = Hardware; + + +#if defined(VIVANTE_NO_3D) + context->entryPipe = gcvPIPE_2D; + context->exitPipe = gcvPIPE_2D; +#elif gcdCMD_NO_2D_CONTEXT + context->entryPipe = gcvPIPE_3D; + context->exitPipe = gcvPIPE_3D; +#else + context->entryPipe + = (((((gctUINT32) (context->hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) ) + ? gcvPIPE_2D + : gcvPIPE_3D; + context->exitPipe = gcvPIPE_3D; +#endif + + /* Get the command buffer requirements. */ + gcmkONERROR(gckHARDWARE_QueryCommandBuffer( + Hardware, + &context->alignment, + &context->reservedHead, + &context->reservedTail + )); + + /* Mark the context as dirty to force loading of the entire state table + the first time. */ + context->dirty = gcvTRUE; + + + /**************************************************************************/ + /* Get the size of the context buffer. ************************************/ + + gcmkONERROR(_InitializeContextBuffer(context)); + + + /**************************************************************************/ + /* Compute the size of the record array. **********************************/ + + context->recordArraySize + = gcmSIZEOF(gcsSTATE_DELTA_RECORD) * context->stateCount; + + + if (context->stateCount > 0) + { + /**************************************************************************/ + /* Allocate and reset the state mapping table. ****************************/ + + /* Allocate the state mapping table. */ + gcmkONERROR(gckOS_Allocate( + Os, + gcmSIZEOF(gcsSTATE_MAP) * context->stateCount, + &pointer + )); + + context->map = pointer; + + /* Zero the state mapping table. */ + gcmkONERROR(gckOS_ZeroMemory( + context->map, gcmSIZEOF(gcsSTATE_MAP) * context->stateCount + )); + + + /**************************************************************************/ + /* Allocate the hint array. ***********************************************/ + +#if gcdSECURE_USER + /* Allocate hints. */ + gcmkONERROR(gckOS_Allocate( + Os, + gcmSIZEOF(gctBOOL) * context->stateCount, + &pointer + )); + + context->hint = pointer; +#endif + } + + /**************************************************************************/ + /* Allocate the context and state delta buffers. **************************/ + + for (i = 0; i < gcdCONTEXT_BUFFER_COUNT; i += 1) + { + /* Allocate a context buffer. */ + gcsCONTEXT_PTR buffer; + + /* Allocate the context buffer structure. */ + gcmkONERROR(gckOS_Allocate( + Os, + gcmSIZEOF(gcsCONTEXT), + &pointer + )); + + buffer = pointer; + + /* Reset the context buffer structure. */ + gcmkVERIFY_OK(gckOS_ZeroMemory( + buffer, gcmSIZEOF(gcsCONTEXT) + )); + + /* Append to the list. */ + if (context->buffer == gcvNULL) + { + buffer->next = buffer; + context->buffer = buffer; + } + else + { + buffer->next = context->buffer->next; + context->buffer->next = buffer; + } + + /* Set the number of delta in the order of creation. */ +#if gcmIS_DEBUG(gcdDEBUG_CODE) + buffer->num = i; +#endif + + /* Create the busy signal. */ + gcmkONERROR(gckOS_CreateSignal( + Os, gcvFALSE, &buffer->signal + )); + + /* Set the signal, buffer is currently not busy. */ + gcmkONERROR(gckOS_Signal( + Os, buffer->signal, gcvTRUE + )); + + /* Create a new physical context buffer. */ + gcmkONERROR(gckOS_AllocateContiguous( + Os, + gcvFALSE, + &context->totalSize, + &buffer->physical, + &pointer + )); + + buffer->logical = pointer; + + /* Set gckEVENT object pointer. */ + buffer->eventObj = Hardware->kernel->eventObj; + + /* Set the pointers to the LINK commands. */ + if (context->linkIndex2D != 0) + { + buffer->link2D = &buffer->logical[context->linkIndex2D]; + } + + if (context->linkIndex3D != 0) + { + buffer->link3D = &buffer->logical[context->linkIndex3D]; + } + + if (context->linkIndexXD != 0) + { + gctPOINTER xdLink; + gctUINT8_PTR xdEntryLogical; + gctSIZE_T xdEntrySize; + gctSIZE_T linkBytes; + + /* Determine LINK parameters. */ + xdLink + = &buffer->logical[context->linkIndexXD]; + + xdEntryLogical + = (gctUINT8_PTR) buffer->logical + + context->entryOffsetXDFrom3D; + + xdEntrySize + = context->bufferSize + - context->entryOffsetXDFrom3D; + + /* Query LINK size. */ + gcmkONERROR(gckHARDWARE_Link( + Hardware, gcvNULL, gcvNULL, 0, &linkBytes + )); + + /* Generate a LINK. */ + gcmkONERROR(gckHARDWARE_Link( + Hardware, + xdLink, + xdEntryLogical, + xdEntrySize, + &linkBytes + )); + } + } + + + /**************************************************************************/ + /* Initialize the context buffers. ****************************************/ + + /* Initialize the current context buffer. */ + gcmkONERROR(_InitializeContextBuffer(context)); + + /* Make all created contexts equal. */ + { + gcsCONTEXT_PTR currContext, tempContext; + + /* Set the current context buffer. */ + currContext = context->buffer; + + /* Get the next context buffer. */ + tempContext = currContext->next; + + /* Loop through all buffers. */ + while (tempContext != currContext) + { + if (tempContext == gcvNULL) + { + gcmkONERROR(gcvSTATUS_NOT_FOUND); + } + + /* Copy the current context. */ + gcmkONERROR(gckOS_MemCopy( + tempContext->logical, + currContext->logical, + context->totalSize + )); + + /* Get the next context buffer. */ + tempContext = tempContext->next; + } + } + + /* Return pointer to the gckCONTEXT object. */ + *Context = context; + + /* Success. */ + gcmkFOOTER_ARG("*Context=0x%08X", *Context); + return gcvSTATUS_OK; + +OnError: + /* Roll back on error. */ + gcmkVERIFY_OK(_DestroyContext(context)); + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************\ +** +** gckCONTEXT_Destroy +** +** Destroy a gckCONTEXT object. +** +** INPUT: +** +** gckCONTEXT Context +** Pointer to an gckCONTEXT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCONTEXT_Destroy( + IN gckCONTEXT Context + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Context=0x%08X", Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); + + /* Destroy the context and all related objects. */ + status = _DestroyContext(Context); + + /* Success. */ + gcmkFOOTER_NO(); + return status; +} + +/******************************************************************************\ +** +** gckCONTEXT_Update +** +** Merge all pending state delta buffers into the current context buffer. +** +** INPUT: +** +** gckCONTEXT Context +** Pointer to an gckCONTEXT object. +** +** gctUINT32 ProcessID +** Current process ID. +** +** gcsSTATE_DELTA_PTR StateDelta +** Pointer to the state delta. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCONTEXT_Update( + IN gckCONTEXT Context, + IN gctUINT32 ProcessID, + IN gcsSTATE_DELTA_PTR StateDelta + ) +{ +#ifndef VIVANTE_NO_3D + gceSTATUS status = gcvSTATUS_OK; + gcsSTATE_DELTA _stateDelta; + gckKERNEL kernel; + gcsCONTEXT_PTR buffer; + gcsSTATE_MAP_PTR map; + gctBOOL needCopy = gcvFALSE; + gcsSTATE_DELTA_PTR nDelta; + gcsSTATE_DELTA_PTR uDelta = gcvNULL; + gcsSTATE_DELTA_PTR kDelta = gcvNULL; + gcsSTATE_DELTA_RECORD_PTR record; + gcsSTATE_DELTA_RECORD_PTR recordArray = gcvNULL; + gctUINT elementCount; + gctUINT address; + gctUINT32 mask; + gctUINT32 data; + gctUINT index; + gctUINT i, j; + +#if gcdSECURE_USER + gcskSECURE_CACHE_PTR cache; +#endif + + gcmkHEADER_ARG( + "Context=0x%08X ProcessID=%d StateDelta=0x%08X", + Context, ProcessID, StateDelta + ); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Context, gcvOBJ_CONTEXT); + + /* Get a shortcut to the kernel object. */ + kernel = Context->hardware->kernel; + + /* Check wehther we need to copy the structures or not. */ + gcmkONERROR(gckOS_QueryNeedCopy(Context->os, ProcessID, &needCopy)); + + /* Allocate the copy buffer for the user record array. */ + if (needCopy && (Context->recordArray == gcvNULL)) + { + /* Allocate the buffer. */ + gcmkONERROR(gckOS_Allocate( + Context->os, + Context->recordArraySize, + (gctPOINTER *) &Context->recordArray + )); + } + + /* Get the current context buffer. */ + buffer = Context->buffer; + + /* Wait until the context buffer becomes available; this will + also reset the signal and mark the buffer as busy. */ + gcmkONERROR(gckOS_WaitSignal( + Context->os, buffer->signal, gcvINFINITE + )); + +#if gcdSECURE_USER + /* Get the cache form the database. */ + gcmkONERROR(gckKERNEL_GetProcessDBCache(kernel, ProcessID, &cache)); +#endif + +#if gcmIS_DEBUG(gcdDEBUG_CODE) && 1 && !defined(VIVANTE_NO_3D) + /* Update current context token. */ + buffer->logical[Context->map[0x0E14].index] + = gcmPTR2INT(Context); +#endif + + /* Are there any pending deltas? */ + if (buffer->deltaCount != 0) + { + /* Get the state map. */ + map = Context->map; + + /* Get the first delta item. */ + uDelta = buffer->delta; + + /* Reset the vertex stream count. */ + elementCount = 0; + + /* Merge all pending deltas. */ + for (i = 0; i < buffer->deltaCount; i += 1) + { + /* Get access to the state delta. */ + gcmkONERROR(gckKERNEL_OpenUserData( + kernel, needCopy, + &_stateDelta, + uDelta, gcmSIZEOF(gcsSTATE_DELTA), + (gctPOINTER *) &kDelta + )); + + /* Get access to the state records. */ + gcmkONERROR(gckKERNEL_OpenUserData( + kernel, needCopy, + Context->recordArray, + kDelta->recordArray, Context->recordArraySize, + (gctPOINTER *) &recordArray + )); + + /* Merge all pending states. */ + for (j = 0; j < kDelta->recordCount; j += 1) + { + if (j >= Context->stateCount) + { + break; + } + + /* Get the current state record. */ + record = &recordArray[j]; + + /* Get the state address. */ + address = record->address; + + /* Make sure the state is a part of the mapping table. */ + if (address >= Context->stateCount) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): State 0x%04X is not mapped.\n", + __FUNCTION__, __LINE__, + address + ); + + continue; + } + + /* Get the state index. */ + index = map[address].index; + + /* Skip the state if not mapped. */ + if (index == 0) + { +#if gcdDEBUG + if ((address != 0x0594) + && (address != 0x0E00) + && (address != 0x0E03) + ) + { +#endif + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): State 0x%04X is not mapped.\n", + __FUNCTION__, __LINE__, + address + ); +#if gcdDEBUG + } +#endif + continue; + } + + /* Get the data mask. */ + mask = record->mask; + + /* Masked states that are being completly reset or regular states. */ + if ((mask == 0) || (mask == ~0U)) + { + /* Get the new data value. */ + data = record->data; + + /* Process special states. */ + if (address == 0x0595) + { + /* Force auto-disable to be disabled. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1))))))) << (0 ? 13:13))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 13:13) - (0 ? 13:13) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 13:13) - (0 ? 13:13) + 1))))))) << (0 ? 13:13))); + } + +#if gcdSECURE_USER + /* Do we need to convert the logical address? */ + if (Context->hint[address]) + { + /* Map handle into physical address. */ + gcmkONERROR(gckKERNEL_MapLogicalToPhysical( + kernel, cache, (gctPOINTER) &data + )); + } +#endif + + /* Set new data. */ + buffer->logical[index] = data; + } + + /* Masked states that are being set partially. */ + else + { + buffer->logical[index] + = (~mask & buffer->logical[index]) + | (mask & record->data); + } + } + + /* Get the element count. */ + if (kDelta->elementCount != 0) + { + elementCount = kDelta->elementCount; + } + + /* Dereference delta. */ + kDelta->refCount -= 1; + gcmkASSERT(kDelta->refCount >= 0); + + /* Get the next state delta. */ + nDelta = kDelta->next; + + /* Get access to the state records. */ + gcmkONERROR(gckKERNEL_CloseUserData( + kernel, needCopy, + gcvFALSE, + kDelta->recordArray, Context->recordArraySize, + (gctPOINTER *) &recordArray + )); + + /* Close access to the current state delta. */ + gcmkONERROR(gckKERNEL_CloseUserData( + kernel, needCopy, + gcvTRUE, + uDelta, gcmSIZEOF(gcsSTATE_DELTA), + (gctPOINTER *) &kDelta + )); + + /* Update the user delta pointer. */ + uDelta = nDelta; + } + + /* Hardware disables all input streams when the stream 0 is programmed, + it then reenables those streams that were explicitely programmed by + the software. Because of this we cannot program the entire array of + values, otherwise we'll get all streams reenabled, but rather program + only those that are actully needed by the software. */ + if (elementCount != 0) + { + gctUINT base; + gctUINT nopCount; + gctUINT32_PTR nop; + gctUINT fe2vsCount = 12; + + if ((((((gctUINT32) (Context->hardware->identity.chipMinorFeatures1)) >> (0 ? 23:23)) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) )) + { + fe2vsCount = 16; + } + + /* Determine the base index of the vertex stream array. */ + base = map[0x0180].index; + + /* Set the proper state count. */ + buffer->logical[base - 1] + = ((((gctUINT32) (buffer->logical[base - 1])) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (elementCount ) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + /* Determine the number of NOP commands. */ + nopCount + = (fe2vsCount / 2) + - (elementCount / 2); + + /* Determine the location of the first NOP. */ + nop = &buffer->logical[base + (elementCount | 1)]; + + /* Fill the unused space with NOPs. */ + for (i = 0; i < nopCount; i += 1) + { + if (nop >= buffer->logical + Context->totalSize) + { + break; + } + + /* Generate a NOP command. */ + *nop = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + /* Advance. */ + nop += 2; + } + } + + /* Reset pending deltas. */ + buffer->deltaCount = 0; + buffer->delta = gcvNULL; + } + + /* Set state delta user pointer. */ + uDelta = StateDelta; + + /* Get access to the state delta. */ + gcmkONERROR(gckKERNEL_OpenUserData( + kernel, needCopy, + &_stateDelta, + uDelta, gcmSIZEOF(gcsSTATE_DELTA), + (gctPOINTER *) &kDelta + )); + + /* State delta cannot be attached to anything yet. */ + if (kDelta->refCount != 0) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): kDelta->refCount = %d (has to be 0).\n", + __FUNCTION__, __LINE__, + kDelta->refCount + ); + } + + /* Attach to all contexts. */ + buffer = Context->buffer; + + do + { + /* Attach to the context if nothing is attached yet. If a delta + is allready attached, all we need to do is to increment + the number of deltas in the context. */ + if (buffer->delta == gcvNULL) + { + buffer->delta = uDelta; + } + + /* Update reference count. */ + kDelta->refCount += 1; + + /* Update counters. */ + buffer->deltaCount += 1; + + /* Get the next context buffer. */ + buffer = buffer->next; + + if (buffer == gcvNULL) + { + gcmkONERROR(gcvSTATUS_NOT_FOUND); + } + } + while (Context->buffer != buffer); + + /* Close access to the current state delta. */ + gcmkONERROR(gckKERNEL_CloseUserData( + kernel, needCopy, + gcvTRUE, + uDelta, gcmSIZEOF(gcsSTATE_DELTA), + (gctPOINTER *) &kDelta + )); + + /* Schedule an event to mark the context buffer as available. */ + gcmkONERROR(gckEVENT_Signal( + buffer->eventObj, buffer->signal, gcvKERNEL_PIXEL + )); + + /* Advance to the next context buffer. */ + Context->buffer = buffer->next; + + /* Return the status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + /* Get access to the state records. */ + if (kDelta != gcvNULL) + { + gcmkVERIFY_OK(gckKERNEL_CloseUserData( + kernel, needCopy, + gcvFALSE, + kDelta->recordArray, Context->recordArraySize, + (gctPOINTER *) &recordArray + )); + } + + /* Close access to the current state delta. */ + gcmkVERIFY_OK(gckKERNEL_CloseUserData( + kernel, needCopy, + gcvTRUE, + uDelta, gcmSIZEOF(gcsSTATE_DELTA), + (gctPOINTER *) &kDelta + )); + + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + return gcvSTATUS_OK; +#endif +} + diff --git a/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.h b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.h new file mode 100644 index 0000000..a5030de --- /dev/null +++ b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_context.h @@ -0,0 +1,146 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_context_h_ +#define __gc_hal_kernel_context_h_ + +#include "gc_hal_kernel_buffer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Maps state locations within the context buffer. */ +typedef struct _gcsSTATE_MAP * gcsSTATE_MAP_PTR; +typedef struct _gcsSTATE_MAP +{ + /* Index of the state in the context buffer. */ + gctUINT index; + + /* State mask. */ + gctUINT32 mask; +} +gcsSTATE_MAP; + +/* Context buffer. */ +typedef struct _gcsCONTEXT * gcsCONTEXT_PTR; +typedef struct _gcsCONTEXT +{ + /* For debugging: the number of context buffer in the order of creation. */ +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gctUINT num; +#endif + + /* Pointer to gckEVENT object. */ + gckEVENT eventObj; + + /* Context busy signal. */ + gctSIGNAL signal; + + /* Physical address of the context buffer. */ + gctPHYS_ADDR physical; + + /* Logical address of the context buffer. */ + gctUINT32_PTR logical; + + /* Pointer to the LINK commands. */ + gctPOINTER link2D; + gctPOINTER link3D; + + /* The number of pending state deltas. */ + gctUINT deltaCount; + + /* Pointer to the first delta to be applied. */ + gcsSTATE_DELTA_PTR delta; + + /* Next context buffer. */ + gcsCONTEXT_PTR next; +} +gcsCONTEXT; + +/* gckCONTEXT structure that hold the current context. */ +struct _gckCONTEXT +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* Command buffer alignment. */ + gctSIZE_T alignment; + gctSIZE_T reservedHead; + gctSIZE_T reservedTail; + + /* Context buffer metrics. */ + gctSIZE_T stateCount; + gctSIZE_T totalSize; + gctSIZE_T bufferSize; + gctUINT32 linkIndex2D; + gctUINT32 linkIndex3D; + gctUINT32 linkIndexXD; + gctUINT32 entryOffset3D; + gctUINT32 entryOffsetXDFrom2D; + gctUINT32 entryOffsetXDFrom3D; + + /* Dirty flags. */ + gctBOOL dirty; + gctBOOL dirty2D; + gctBOOL dirty3D; + gcsCONTEXT_PTR dirtyBuffer; + + /* State mapping. */ + gcsSTATE_MAP_PTR map; + + /* List of context buffers. */ + gcsCONTEXT_PTR buffer; + + /* A copy of the user record array. */ + gctUINT recordArraySize; + gcsSTATE_DELTA_RECORD_PTR recordArray; + + /* Requested pipe select for context. */ + gcePIPE_SELECT entryPipe; + gcePIPE_SELECT exitPipe; + + /* Variables used for building state buffer. */ + gctUINT32 lastAddress; + gctSIZE_T lastSize; + gctUINT32 lastIndex; + gctBOOL lastFixed; + + /* Hint array. */ +#if gcdSECURE_USER + gctBOOL_PTR hint; +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_context_h_ */ + diff --git a/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c new file mode 100644 index 0000000..08d346e --- /dev/null +++ b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.c @@ -0,0 +1,5267 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal.h" +#include "gc_hal_kernel.h" + +#define _GC_OBJ_ZONE gcvZONE_HARDWARE + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ +static gceSTATUS +_ResetGPU( + IN gckHARDWARE Hardware, + IN gckOS Os, + IN gceCORE Core + ); + +static gceSTATUS +_IdentifyHardware( + IN gckOS Os, + IN gceCORE Core, + OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity + ) +{ + gceSTATUS status; + + gctUINT32 chipIdentity; + + gctUINT32 streamCount = 0; + gctUINT32 registerMax = 0; + gctUINT32 threadCount = 0; + gctUINT32 shaderCoreCount = 0; + gctUINT32 vertexCacheSize = 0; + gctUINT32 vertexOutputBufferSize = 0; + gctUINT32 pixelPipes = 0; + gctUINT32 instructionCount = 0; + gctUINT32 numConstants = 0; + gctUINT32 bufferSize = 0; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /*************************************************************************** + ** Get chip ID and revision. + */ + + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00018, + &chipIdentity)); + + /* Special case for older graphic cores. */ + if (((((gctUINT32) (chipIdentity)) >> (0 ? 31:24) & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:24) - (0 ? 31:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:24) - (0 ? 31:24) + 1)))))))) + { + Identity->chipModel = gcv500; + Identity->chipRevision = (((((gctUINT32) (chipIdentity)) >> (0 ? 15:12)) & ((gctUINT32) ((((1 ? 15:12) - (0 ? 15:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:12) - (0 ? 15:12) + 1)))))) ); + } + + else + { + /* Read chip identity register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00020, + (gctUINT32_PTR) &Identity->chipModel)); + + /* !!!! HACK ALERT !!!! */ + /* Because people change device IDs without letting software know + ** about it - here is the hack to make it all look the same. Only + ** for GC400 family. Next time - TELL ME!!! */ + if (((Identity->chipModel & 0xFF00) == 0x0400) + && (Identity->chipModel != 0x0420)) + { + Identity->chipModel = (gceCHIPMODEL) (Identity->chipModel & 0x0400); + } + + /* Read CHIP_REV register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00024, + &Identity->chipRevision)); + + if ((Identity->chipModel == gcv300) + && (Identity->chipRevision == 0x2201) + ) + { + gctUINT32 chipDate; + gctUINT32 chipTime; + + /* Read date and time registers. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00028, + &chipDate)); + + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x0002C, + &chipTime)); + + if ((chipDate == 0x20080814) && (chipTime == 0x12051100)) + { + /* This IP has an ECO; put the correct revision in it. */ + Identity->chipRevision = 0x1051; + } + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipModel=%X", + Identity->chipModel); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipRevision=%X", + Identity->chipRevision); + + + /*************************************************************************** + ** Get chip features. + */ + + /* Read chip feature register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x0001C, + &Identity->chipFeatures)); + +#ifndef VIVANTE_NO_3D + /* Disable fast clear on GC700. */ + if (Identity->chipModel == gcv700) + { + Identity->chipFeatures + = ((((gctUINT32) (Identity->chipFeatures)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } +#endif + + if (((Identity->chipModel == gcv500) && (Identity->chipRevision < 2)) + || ((Identity->chipModel == gcv300) && (Identity->chipRevision < 0x2000)) + ) + { + /* GC500 rev 1.x and GC300 rev < 2.0 doesn't have these registers. */ + Identity->chipMinorFeatures = 0; + Identity->chipMinorFeatures1 = 0; + Identity->chipMinorFeatures2 = 0; + Identity->chipMinorFeatures3 = 0; + } + else + { + /* Read chip minor feature register #0. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00034, + &Identity->chipMinorFeatures)); + + if (((((gctUINT32) (Identity->chipMinorFeatures)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) + ) + { + /* Read chip minor featuress register #1. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00074, + &Identity->chipMinorFeatures1)); + + /* Read chip minor featuress register #2. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00084, + &Identity->chipMinorFeatures2)); + + /*Identity->chipMinorFeatures2 &= ~(0x1 << 3);*/ + + /* Read chip minor featuress register #1. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00088, + &Identity->chipMinorFeatures3)); + } + else + { + /* Chip doesn't has minor features register #1 or 2 or 3. */ + Identity->chipMinorFeatures1 = 0; + Identity->chipMinorFeatures2 = 0; + Identity->chipMinorFeatures3 = 0; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipFeatures=0x%08X", + Identity->chipFeatures); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipMinorFeatures=0x%08X", + Identity->chipMinorFeatures); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipMinorFeatures1=0x%08X", + Identity->chipMinorFeatures1); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipMinorFeatures2=0x%08X", + Identity->chipMinorFeatures2); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Identity: chipMinorFeatures3=0x%08X", + Identity->chipMinorFeatures3); + + /*************************************************************************** + ** Get chip specs. + */ + + if (((((gctUINT32) (Identity->chipMinorFeatures)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) + { + gctUINT32 specs, specs2; + + /* Read gcChipSpecs register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00048, + &specs)); + + /* Extract the fields. */ + streamCount = (((((gctUINT32) (specs)) >> (0 ? 3:0)) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1)))))) ); + registerMax = (((((gctUINT32) (specs)) >> (0 ? 7:4)) & ((gctUINT32) ((((1 ? 7:4) - (0 ? 7:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:4) - (0 ? 7:4) + 1)))))) ); + threadCount = (((((gctUINT32) (specs)) >> (0 ? 11:8)) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1)))))) ); + shaderCoreCount = (((((gctUINT32) (specs)) >> (0 ? 24:20)) & ((gctUINT32) ((((1 ? 24:20) - (0 ? 24:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:20) - (0 ? 24:20) + 1)))))) ); + vertexCacheSize = (((((gctUINT32) (specs)) >> (0 ? 16:12)) & ((gctUINT32) ((((1 ? 16:12) - (0 ? 16:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:12) - (0 ? 16:12) + 1)))))) ); + vertexOutputBufferSize = (((((gctUINT32) (specs)) >> (0 ? 31:28)) & ((gctUINT32) ((((1 ? 31:28) - (0 ? 31:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:28) - (0 ? 31:28) + 1)))))) ); + pixelPipes = (((((gctUINT32) (specs)) >> (0 ? 27:25)) & ((gctUINT32) ((((1 ? 27:25) - (0 ? 27:25) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:25) - (0 ? 27:25) + 1)))))) ); + + /* Read gcChipSpecs2 register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Os, Core, + 0x00080, + &specs2)); + + instructionCount = (((((gctUINT32) (specs2)) >> (0 ? 15:8)) & ((gctUINT32) ((((1 ? 15:8) - (0 ? 15:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:8) - (0 ? 15:8) + 1)))))) ); + numConstants = (((((gctUINT32) (specs2)) >> (0 ? 31:16)) & ((gctUINT32) ((((1 ? 31:16) - (0 ? 31:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:16) - (0 ? 31:16) + 1)))))) ); + bufferSize = (((((gctUINT32) (specs2)) >> (0 ? 7:0)) & ((gctUINT32) ((((1 ? 7:0) - (0 ? 7:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:0) - (0 ? 7:0) + 1)))))) ); + } + + /* Get the number of pixel pipes. */ + Identity->pixelPipes = gcmMAX(pixelPipes, 1); + + /* Get the stream count. */ + Identity->streamCount = (streamCount != 0) + ? streamCount + : (Identity->chipModel >= gcv1000) ? 4 : 1; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: streamCount=%u%s", + Identity->streamCount, + (streamCount == 0) ? " (default)" : ""); + + /* Get the vertex output buffer size. */ + Identity->vertexOutputBufferSize = (vertexOutputBufferSize != 0) + ? 1 << vertexOutputBufferSize + : (Identity->chipModel == gcv400) + ? (Identity->chipRevision < 0x4000) ? 512 + : (Identity->chipRevision < 0x4200) ? 256 + : 128 + : (Identity->chipModel == gcv530) + ? (Identity->chipRevision < 0x4200) ? 512 + : 128 + : 512; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexOutputBufferSize=%u%s", + Identity->vertexOutputBufferSize, + (vertexOutputBufferSize == 0) ? " (default)" : ""); + + /* Get the maximum number of threads. */ + Identity->threadCount = (threadCount != 0) + ? 1 << threadCount + : (Identity->chipModel == gcv400) ? 64 + : (Identity->chipModel == gcv500) ? 128 + : (Identity->chipModel == gcv530) ? 128 + : 256; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: threadCount=%u%s", + Identity->threadCount, + (threadCount == 0) ? " (default)" : ""); + + /* Get the number of shader cores. */ + Identity->shaderCoreCount = (shaderCoreCount != 0) + ? shaderCoreCount + : (Identity->chipModel >= gcv1000) ? 2 + : 1; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: shaderCoreCount=%u%s", + Identity->shaderCoreCount, + (shaderCoreCount == 0) ? " (default)" : ""); + + /* Get the vertex cache size. */ + Identity->vertexCacheSize = (vertexCacheSize != 0) + ? vertexCacheSize + : 8; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: vertexCacheSize=%u%s", + Identity->vertexCacheSize, + (vertexCacheSize == 0) ? " (default)" : ""); + + /* Get the maximum number of temporary registers. */ + Identity->registerMax = (registerMax != 0) + /* Maximum of registerMax/4 registers are accessible to 1 shader */ + ? 1 << registerMax + : (Identity->chipModel == gcv400) ? 32 + : 64; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: registerMax=%u%s", + Identity->registerMax, + (registerMax == 0) ? " (default)" : ""); + + /* Get the instruction count. */ + Identity->instructionCount = (instructionCount == 0) ? 256 + : (instructionCount == 1) ? 1024 + : (instructionCount == 2) ? 2048 + : 256; + + if (Identity->chipModel == gcv2000 && Identity->chipRevision == 0x5108) + { + Identity->instructionCount = 512; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: instructionCount=%u%s", + Identity->instructionCount, + (instructionCount == 0) ? " (default)" : ""); + + /* Get the number of constants. */ + Identity->numConstants = numConstants; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: numConstants=%u%s", + Identity->numConstants, + (numConstants == 0) ? " (default)" : ""); + + /* Get the buffer size. */ + Identity->bufferSize = bufferSize; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Specs: bufferSize=%u%s", + Identity->bufferSize, + (bufferSize == 0) ? " (default)" : ""); + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdPOWEROFF_TIMEOUT +void +_PowerTimerFunction( + gctPOINTER Data + ) +{ + gckHARDWARE hardware = (gckHARDWARE)Data; + gcmkVERIFY_OK( + gckHARDWARE_SetPowerManagementState(hardware, gcvPOWER_OFF_TIMEOUT)); +} +#endif + +/******************************************************************************\ +****************************** gckHARDWARE API code ***************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckHARDWARE_Construct +** +** Construct a new gckHARDWARE object. +** +** INPUT: +** +** gckOS Os +** Pointer to an initialized gckOS object. +** +** gceCORE Core +** Specified core. +** +** OUTPUT: +** +** gckHARDWARE * Hardware +** Pointer to a variable that will hold the pointer to the gckHARDWARE +** object. +*/ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + IN gceCORE Core, + OUT gckHARDWARE * Hardware + ) +{ + gceSTATUS status; + gckHARDWARE hardware = gcvNULL; + gctUINT16 data = 0xff00; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Hardware != gcvNULL); + + /* Enable the GPU. */ + gcmkONERROR(gckOS_SetGPUPower(Os, gcvTRUE, gcvTRUE)); + gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00000, 0)); + + /* Allocate the gckHARDWARE object. */ + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(struct _gckHARDWARE), + &pointer)); + + hardware = (gckHARDWARE) pointer; + + /* Initialize the gckHARDWARE object. */ + hardware->object.type = gcvOBJ_HARDWARE; + hardware->os = Os; + hardware->core = Core; + + /* Identify the hardware. */ + gcmkONERROR(_IdentifyHardware(Os, Core, &hardware->identity)); + + /* Determine the hardware type */ + switch (hardware->identity.chipModel) + { + case gcv350: + case gcv355: + hardware->type = gcvHARDWARE_VG; + break; + + case gcv300: + case gcv320: + hardware->type = gcvHARDWARE_2D; + break; + + default: + hardware->type = gcvHARDWARE_3D; + + if ((((((gctUINT32) (hardware->identity.chipFeatures)) >> (0 ? 9:9)) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) )) + { + hardware->type = (gceHARDWARE_TYPE) (hardware->type | gcvHARDWARE_2D); + } + } + + hardware->powerBaseAddress + = ((hardware->identity.chipModel == gcv300) + && (hardware->identity.chipRevision < 0x2000)) + ? 0x0100 + : 0x0000; + + /* _ResetGPU need powerBaseAddress. */ + status = _ResetGPU(hardware, Os, Core); + + if (status != gcvSTATUS_OK) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "_ResetGPU failed: status=%d\n", status); + } + + hardware->powerMutex = gcvNULL; + + hardware->mmuVersion + = (((((gctUINT32) (hardware->identity.chipMinorFeatures1)) >> (0 ? 28:28)) & ((gctUINT32) ((((1 ? 28:28) - (0 ? 28:28) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 28:28) - (0 ? 28:28) + 1)))))) ); + + /* Determine whether bug fixes #1 are present. */ + hardware->extraEventStates = ((((gctUINT32) (hardware->identity.chipMinorFeatures1)) >> (0 ? 3:3) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))); + + /* Check if big endian */ + hardware->bigEndian = (*(gctUINT8 *)&data == 0xff); + + /* Initialize the fast clear. */ + gcmkONERROR(gckHARDWARE_SetFastClear(hardware, -1, -1)); + +#if !gcdENABLE_128B_MERGE && 1 && 1 + + if (((((gctUINT32) (hardware->identity.chipMinorFeatures2)) >> (0 ? 21:21) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1)))))))) + { + /* 128B merge is turned on by default. Disable it. */ + gcmkONERROR(gckOS_WriteRegisterEx(Os, Core, 0x00558, 0)); + } + +#endif + + /* Set power state to ON. */ + hardware->chipPowerState = gcvPOWER_ON; + hardware->clockState = gcvTRUE; + hardware->powerState = gcvTRUE; + hardware->lastWaitLink = ~0U; + hardware->globalSemaphore = gcvNULL; + + gcmkONERROR(gckOS_CreateMutex(Os, &hardware->powerMutex)); + gcmkONERROR(gckOS_CreateSemaphore(Os, &hardware->globalSemaphore)); + +#if gcdPOWEROFF_TIMEOUT + hardware->powerOffTimeout = gcdPOWEROFF_TIMEOUT; + + gcmkVERIFY_OK(gckOS_CreateTimer(Os, + (gctPOINTER)_PowerTimerFunction, + (gctPOINTER)hardware, + &hardware->powerOffTimer)); +#endif + + gcmkONERROR(gckOS_AtomConstruct(Os, &hardware->pageTableDirty)); + + /* Return pointer to the gckHARDWARE object. */ + *Hardware = hardware; + + /* Success. */ + gcmkFOOTER_ARG("*Hardware=0x%x", *Hardware); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (hardware != gcvNULL) + { + /* Turn off the power. */ + gcmkVERIFY_OK(gckOS_SetGPUPower(Os, gcvFALSE, gcvFALSE)); + + if (hardware->globalSemaphore != gcvNULL) + { + /* Destroy the global semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySemaphore(Os, + hardware->globalSemaphore)); + } + + if (hardware->powerMutex != gcvNULL) + { + /* Destroy the power mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, hardware->powerMutex)); + } + +#if gcdPOWEROFF_TIMEOUT + if (hardware->powerOffTimer != gcvNULL) + { + gcmkVERIFY_OK(gckOS_StopTimer(Os, hardware->powerOffTimer)); + gcmkVERIFY_OK(gckOS_DestoryTimer(Os, hardware->powerOffTimer)); + } +#endif + + if (hardware->pageTableDirty != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(Os, hardware->pageTableDirty)); + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, hardware)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Destroy +** +** Destroy an gckHARDWARE object. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Turn off the power. */ + gcmkVERIFY_OK(gckOS_SetGPUPower(Hardware->os, gcvFALSE, gcvFALSE)); + + /* Destroy the power semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySemaphore(Hardware->os, + Hardware->globalSemaphore)); + + /* Destroy the power mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Hardware->os, Hardware->powerMutex)); + +#if gcdPOWEROFF_TIMEOUT + gcmkVERIFY_OK(gckOS_StopTimer(Hardware->os, Hardware->powerOffTimer)); + gcmkVERIFY_OK(gckOS_DestoryTimer(Hardware->os, Hardware->powerOffTimer)); +#endif + + gcmkVERIFY_OK(gckOS_AtomDestroy(Hardware->os, Hardware->pageTableDirty)); + + /* Mark the object as unknown. */ + Hardware->object.type = gcvOBJ_UNKNOWN; + + /* Free the object. */ + gcmkONERROR(gcmkOS_SAFE_FREE(Hardware->os, Hardware)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_GetType +** +** Get the hardware type. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gceHARDWARE_TYPE * Type +** Pointer to a variable that receives the type of hardware object. +*/ +gceSTATUS +gckHARDWARE_GetType( + IN gckHARDWARE Hardware, + OUT gceHARDWARE_TYPE * Type + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + gcmkVERIFY_ARGUMENT(Type != gcvNULL); + + *Type = Hardware->type; + + gcmkFOOTER_ARG("*Type=%d", *Type); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_InitializeHardware +** +** Initialize the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gctUINT32 baseAddress; + gctUINT32 chipRev; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the chip revision register. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00024, + &chipRev)); + + if (chipRev != Hardware->identity.chipRevision) + { + /* Chip is not there! */ + gcmkONERROR(gcvSTATUS_CONTEXT_LOSSED); + } + + /* Disable isolate GPU bit. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00000, + ((((gctUINT32) (0x00000100)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))))); + + /* Reset memory counters. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0003C, + ~0U)); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0003C, + 0)); + + /* Get the system's physical base address. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + /* Program the base addesses. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0041C, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00418, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00428, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00420, + baseAddress)); + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00424, + baseAddress)); + +#if !VIVANTE_PROFILER && 1 + { + gctUINT32 data; + + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + Hardware->powerBaseAddress + + 0x00100, + &data)); + + /* Enable clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + + if ((Hardware->identity.chipRevision == 0x4301) + || (Hardware->identity.chipRevision == 0x4302) + ) + { + /* Disable stall module level clock gating for 4.3.0.1 and 4.3.0.2 + ** revisions. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); + } + + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + Hardware->powerBaseAddress + + 0x00100, + data)); + +#ifndef VIVANTE_NO_3D + /* Disable PE clock gating on revs < 5.0 when HZ is present without a + ** bug fix. */ + if ((Hardware->identity.chipRevision < 0x5000) + && ((((gctUINT32) (Hardware->identity.chipMinorFeatures1)) >> (0 ? 9:9) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1)))))) == (0x0 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) + && ((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 27:27) & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 27:27) - (0 ? 27:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:27) - (0 ? 27:27) + 1))))))) + ) + { + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + Hardware->powerBaseAddress + + 0x00104, + &data)); + + /* Disable PE clock gating. */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); + + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + Hardware->powerBaseAddress + + 0x00104, + data)); + } + +#endif + } +#endif + + /* Special workaround for this core + ** Make sure pulse eater kicks in only when SH is idle */ + if (Hardware->identity.chipModel == gcv4000 && + Hardware->identity.chipRevision == 0x5208) + { + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0010C, + ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1))))))) << (0 ? 23:23))))); + } + + /* Special workaround for this core + ** Make sure FE and TX are on different buses */ + if ((Hardware->identity.chipModel == gcv2000) + && (Hardware->identity.chipRevision == 0x5108)) + { + gctUINT32 data; + + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00480, + &data)); + + /* Set FE bus to one, TX bus to zero */ + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); + data = ((((gctUINT32) (data)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))); + + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00480, + data)); + } + + /* Test if MMU is initialized. */ + if ((Hardware->kernel != gcvNULL) + && (Hardware->kernel->mmu != gcvNULL) + ) + { + /* Reset MMU. */ + if (Hardware->mmuVersion == 0) + { + gcmkONERROR( + gckHARDWARE_SetMMU(Hardware, + Hardware->kernel->mmu->pageTableLogical)); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryMemory +** +** Query the amount of memory available on the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * InternalSize +** Pointer to a variable that will hold the size of the internal video +** memory in bytes. If 'InternalSize' is gcvNULL, no information of the +** internal memory will be returned. +** +** gctUINT32 * InternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctUINT32 * InternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the internal video memory. This pointer cannot be gcvNULL if +** 'InternalSize' is also non-gcvNULL. +** +** gctSIZE_T * ExternalSize +** Pointer to a variable that will hold the size of the external video +** memory in bytes. If 'ExternalSize' is gcvNULL, no information of the +** external memory will be returned. +** +** gctUINT32 * ExternalBaseAddress +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * ExternalAlignment +** Pointer to a variable that will hold the hardware's base address for +** the external video memory. This pointer cannot be gcvNULL if +** 'ExternalSize' is also non-gcvNULL. +** +** gctUINT32 * HorizontalTileSize +** Number of horizontal pixels per tile. If 'HorizontalTileSize' is +** gcvNULL, no horizontal pixel per tile will be returned. +** +** gctUINT32 * VerticalTileSize +** Number of vertical pixels per tile. If 'VerticalTileSize' is +** gcvNULL, no vertical pixel per tile will be returned. +*/ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (InternalSize != gcvNULL) + { + /* No internal memory. */ + *InternalSize = 0; + } + + if (ExternalSize != gcvNULL) + { + /* No external memory. */ + *ExternalSize = 0; + } + + if (HorizontalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *HorizontalTileSize = 4; + } + + if (VerticalTileSize != gcvNULL) + { + /* 4x4 tiles. */ + *VerticalTileSize = 4; + } + + /* Success. */ + gcmkFOOTER_ARG("*InternalSize=%lu *InternalBaseAddress=0x%08x " + "*InternalAlignment=0x%08x *ExternalSize=%lu " + "*ExternalBaseAddress=0x%08x *ExtenalAlignment=0x%08x " + "*HorizontalTileSize=%u *VerticalTileSize=%u", + gcmOPT_VALUE(InternalSize), + gcmOPT_VALUE(InternalBaseAddress), + gcmOPT_VALUE(InternalAlignment), + gcmOPT_VALUE(ExternalSize), + gcmOPT_VALUE(ExternalBaseAddress), + gcmOPT_VALUE(ExternalAlignment), + gcmOPT_VALUE(HorizontalTileSize), + gcmOPT_VALUE(VerticalTileSize)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryChipIdentity +** +** Query the identity of the hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity +** Pointer to the identity structure. +** +*/ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity + ) +{ + gctUINT32 features; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Identity != gcvNULL); + + /* Return chip model and revision. */ + Identity->chipModel = Hardware->identity.chipModel; + Identity->chipRevision = Hardware->identity.chipRevision; + + /* Return feature set. */ + features = Hardware->identity.chipFeatures; + + if ((((((gctUINT32) (features)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Override fast clear by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Hardware->allowFastClear) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + if ((((((gctUINT32) (features)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) )) + { + /* Override compression by command line. */ + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) ((gctUINT32) (Hardware->allowCompression) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); + } + + /* Mark 2D pipe as available for GC500.0 through GC500.2 and GC300, + ** since they did not have this bit. */ + if (((Hardware->identity.chipModel == gcv500) && (Hardware->identity.chipRevision <= 2)) + || (Hardware->identity.chipModel == gcv300) + ) + { + features = ((((gctUINT32) (features)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))); + } + + Identity->chipFeatures = features; + + /* Return minor features. */ + Identity->chipMinorFeatures = Hardware->identity.chipMinorFeatures; + Identity->chipMinorFeatures1 = Hardware->identity.chipMinorFeatures1; + Identity->chipMinorFeatures2 = Hardware->identity.chipMinorFeatures2; + Identity->chipMinorFeatures3 = Hardware->identity.chipMinorFeatures3; + + /* Return chip specs. */ + Identity->streamCount = Hardware->identity.streamCount; + Identity->registerMax = Hardware->identity.registerMax; + Identity->threadCount = Hardware->identity.threadCount; + Identity->shaderCoreCount = Hardware->identity.shaderCoreCount; + Identity->vertexCacheSize = Hardware->identity.vertexCacheSize; + Identity->vertexOutputBufferSize = Hardware->identity.vertexOutputBufferSize; + Identity->pixelPipes = Hardware->identity.pixelPipes; + Identity->instructionCount = Hardware->identity.instructionCount; + Identity->numConstants = Hardware->identity.numConstants; + Identity->bufferSize = Hardware->identity.bufferSize; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_SplitMemory +** +** Split a hardware specific memory address into a pool and offset. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctUINT32 Address +** Address in hardware specific format. +** +** OUTPUT: +** +** gcePOOL * Pool +** Pointer to a variable that will hold the pool type for the address. +** +** gctUINT32 * Offset +** Pointer to a variable that will hold the offset for the address. +*/ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Addres=0x%08x", Hardware, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + gcmkVERIFY_ARGUMENT(Offset != gcvNULL); + + /* Dispatch on memory type. */ + switch ((((((gctUINT32) (Address)) >> (0 ? 31:31)) & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1)))))) )) + { + case 0x0: + /* System memory. */ + *Pool = gcvPOOL_SYSTEM; + break; + + case 0x1: + /* Virtual memory. */ + *Pool = gcvPOOL_VIRTUAL; + break; + + default: + /* Invalid memory type. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Return offset of address. */ + *Offset = (((((gctUINT32) (Address)) >> (0 ? 30:0)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1)))))) ); + + /* Success. */ + gcmkFOOTER_ARG("*Pool=%d *Offset=0x%08x", *Pool, *Offset); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Execute +** +** Kickstart the hardware's command processor with an initialized command +** buffer. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of command buffer. +** +** gctSIZE_T Bytes +** Number of bytes for the prefetch unit (until after the first LINK). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + gctUINT32 address = 0, control; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Bytes=%lu", + Hardware, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + +#ifdef __QNXNTO__ + if (PhysicalAddresses && (Hardware->mmuVersion == 0)) + { + /* Convert physical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertPhysical(Hardware, Physical, &address)); + } + else + { +#endif + /* Convert logical into hardware specific address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); +#ifdef __QNXNTO__ + } +#endif + + /* Enable all events. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00014, ~0U)); + + /* Write address register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00654, address)); + + /* Build control register. */ + control = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1))))))) << (0 ? 16:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) ((Bytes + 7) >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + /* Set big endian */ + if (Hardware->bigEndian) + { + control |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))) | (((gctUINT32) (0x2 & ((gctUINT32) ((((1 ? 21:20) - (0 ? 21:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:20) - (0 ? 21:20) + 1))))))) << (0 ? 21:20))); + } + + /* Write control register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00658, control)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Started command buffer @ 0x%08x", + address); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_WaitLink +** +** Append a WAIT/LINK command sequence at the specified location in the command +** queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT/LINK command sequence at or gcvNULL just to query the size of the +** WAIT/LINK command sequence. +** +** gctUINT32 Offset +** Offset into command buffer required for alignment. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT/LINK command +** sequence. If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** by the WAIT/LINK command sequence. If 'Bytes' is gcvNULL, nothing will +** be returned. +** +** gctUINT32 * WaitOffset +** Pointer to a variable that will receive the offset of the WAIT command +** from the specified logcial pointer. +** If 'WaitOffset' is gcvNULL nothing will be returned. +** +** gctSIZE_T * WaitSize +** Pointer to a variable that will receive the number of bytes used by +** the WAIT command. If 'LinkSize' is gcvNULL nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctUINT32 * WaitOffset, + OUT gctSIZE_T * WaitSize + ) +{ + static const gctUINT waitCount = 200; + + gceSTATUS status; + gctUINT32 address; + gctUINT32_PTR logical; + gctSIZE_T bytes; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x *Bytes=%lu", + Hardware, Logical, Offset, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical != gcvNULL) || (Bytes != gcvNULL)); + + /* Compute number of bytes required. */ +#if gcd6000_SUPPORT + bytes = gcmALIGN(Offset + 96, 8) - Offset; +#else + bytes = gcmALIGN(Offset + 16, 8) - Offset; +#endif + + /* Cast the input pointer. */ + logical = (gctUINT32_PTR) Logical; + + if (logical != gcvNULL) + { + /* Not enough space? */ + if (*Bytes < bytes) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Convert logical into hardware specific address. */ + gcmkONERROR(gckHARDWARE_ConvertLogical(Hardware, logical, &address)); + + /* Store the WAIT/LINK address. */ + Hardware->lastWaitLink = address; + + /* Append WAIT(count). */ + logical[0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (waitCount) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + +#if gcd6000_SUPPORT + /* Send FE-PE sempahore token. */ + logical[2] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[3] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* Send FE-PE stall token. */ + logical[4] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0F00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[5] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /*************************************************************/ + /* Enable chip ID 0. */ + logical[6] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | (1 << 0); + + /* Send semaphore from FE to ChipID 1. */ + logical[8] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[9] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))); + + /* Send semaphore from FE to ChipID 1. */ + logical[10] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + logical[11] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))); + + /*************************************************************/ + /* Enable chip ID 1. */ + logical[12] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | (1 << 1); + + /* Send semaphore from FE to ChipID 1. */ + logical[14] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[15] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))); + + /* Wait for semaphore from ChipID 0. */ + logical[16] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + logical[17] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x0F & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))); + + /*************************************************************/ + /* Enable all chips. */ + logical[18] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x0D & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | (0xFFFF); + + /* LoadState(AQFlush, 1), flush. */ + logical[20] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[21] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); + + /* Append LINK(2, address). */ + logical[22] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[23] = address; +#else + /* Append LINK(2, address). */ + logical[2] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[3] = address; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: WAIT %u", address, waitCount + ); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: LINK 0x%08x, #%lu", + address + 8, address, bytes + ); +#endif + + if (WaitOffset != gcvNULL) + { + /* Return the offset pointer to WAIT command. */ + *WaitOffset = 0; + } + + if (WaitSize != gcvNULL) + { + /* Return number of bytes used by the WAIT command. */ + *WaitSize = 8; + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT/LINK command + ** sequence. */ + *Bytes = bytes; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu *WaitOffset=0x%x *WaitSize=%lu", + gcmOPT_VALUE(Bytes), gcmOPT_VALUE(WaitOffset), + gcmOPT_VALUE(WaitSize)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_End +** +** Append an END command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** END command at or gcvNULL just to query the size of the END command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the END command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the END command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append END. */ + logical[0] = + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x02 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: END", Logical); + + /* Make sure the CPU writes out the data to memory. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, Logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the END command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Nop +** +** Append a NOP command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** NOP command at or gcvNULL just to query the size of the NOP command. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the NOP command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append NOP. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x03 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "0x%x: NOP", Logical); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the NOP command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Wait +** +** Append a WAIT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** WAIT command at or gcvNULL just to query the size of the WAIT command. +** +** gctUINT32 Count +** Number of cycles to wait. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the WAIT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the NOP command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ) +{ + gceSTATUS status; + gctUINT32_PTR logical; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Count=%u *Bytes=%lu", + Hardware, Logical, Count, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Cast the input pointer. */ + logical = (gctUINT32_PTR) Logical; + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append WAIT. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (Count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + { + gctUINT32 address; + + /* Convert logical into hardware specific address. */ + gcmkONERROR(gckHARDWARE_ConvertLogical( + Hardware, logical, &address + )); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: WAIT %u", address, Count + ); + } +#endif + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the WAIT command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Event +** +** Append an EVENT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the EVENT command at or gcvNULL just to query the size of the EVENT +** command. +** +** gctUINT8 Event +** Event ID to program. +** +** gceKERNEL_WHERE FromWhere +** Location of the pipe to send the event. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the EVENT command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the EVENT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT size; + gctUINT32 destination = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Event=%u FromWhere=%d *Bytes=%lu", + Hardware, Logical, Event, FromWhere, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + gcmkVERIFY_ARGUMENT(Event < 32); + + /* Determine the size of the command. */ + +#if gcdUSE_OPENCL + /* Temporary workaround for lost events */ + size = gcmALIGN(8 + (1 + 5) * 4 * 20, 8); /* EVENT + 100 STATES */ +#else + size = (Hardware->extraEventStates && (FromWhere == gcvKERNEL_PIXEL)) + ? gcmALIGN(8 + (1 + 5) * 4, 8) /* EVENT + 5 STATES */ + : 8; +#endif + + if (Logical != gcvNULL) + { + if (*Bytes < size) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + switch (FromWhere) + { + case gcvKERNEL_COMMAND: + /* From command processor. */ +#if gcdUSE_OPENCL + /* Send all events via PE */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); +#else + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))); +#endif + break; + + case gcvKERNEL_PIXEL: + /* From pixel engine. */ + destination = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); + break; + + default: + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Append EVENT(Event, destiantion). */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E01) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = ((((gctUINT32) (destination)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) ((gctUINT32) (Event) & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))); + + /* Make sure the event ID gets written out before GPU can access it. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + { + gctUINT32 phys; + gckOS_GetPhysicalAddress(Hardware->os, Logical, &phys); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%08x: EVENT %d", phys, Event); + } +#endif + + /* Append the extra states. These are needed for the chips that do not + ** support back-to-back events due to the async interface. The extra + ** states add the necessary delay to ensure that event IDs do not + ** collide. */ + if (size > 8) + { +#if gcdUSE_OPENCL + gctUINT i; + + for (i = 0; i < 20; i++) + { + logical[i*6+2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + logical[i*6+3] = 0; + logical[i*6+4] = 0; + logical[i*6+5] = 0; + logical[i*6+6] = 0; + logical[i*6+7] = 0; + } +#else + logical[2] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0100) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + logical[3] = 0; + logical[4] = 0; + logical[5] = 0; + logical[6] = 0; + logical[7] = 0; +#endif + } + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the EVENT command. */ + *Bytes = size; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_PipeSelect +** +** Append a PIPESELECT command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the PIPESELECT command at or gcvNULL just to query the size of the +** PIPESELECT command. +** +** gcePIPE_SELECT Pipe +** Pipe value to select. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the PIPESELECT command. +** If 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the PIPESELECT command. If 'Bytes' is gcvNULL, nothing will be +** returned. +*/ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gcePIPE_SELECT Pipe, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Pipe=%d *Bytes=%lu", + Hardware, Logical, Pipe, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + /* Append a PipeSelect. */ + if (Logical != gcvNULL) + { + gctUINT32 flush, stall; + + if (*Bytes < 32) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + flush = (Pipe == gcvPIPE_2D) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) + : ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); + + stall = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* LoadState(AQFlush, 1), flush. */ + logical[0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] + = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH 0x%x", logical, flush); + + /* LoadState(AQSempahore, 1), stall. */ + logical[2] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + logical[3] + = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: SEMAPHORE 0x%x", logical + 2, stall); + + /* Stall, stall. */ + logical[4] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + logical[5] = stall; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: STALL 0x%x", logical + 4, stall); + + /* LoadState(AQPipeSelect, 1), pipe. */ + logical[6] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E00) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[7] = (Pipe == gcvPIPE_2D) + ? 0x1 + : 0x0; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: PIPE %d", logical + 6, Pipe); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the PIPESELECT command. */ + *Bytes = 32; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Link +** +** Append a LINK command at the specified location in the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Pointer to the current location inside the command queue to append +** the LINK command at or gcvNULL just to query the size of the LINK +** command. +** +** gctPOINTER FetchAddress +** Logical address of destination of LINK. +** +** gctSIZE_T FetchSize +** Number of bytes in destination of LINK. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes available for the LINK command. If +** 'Logical' is gcvNULL, this argument will be ignored. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that will receive the number of bytes required +** for the LINK command. If 'Bytes' is gcvNULL, nothing will be returned. +*/ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ) +{ + gceSTATUS status; + gctSIZE_T bytes; + gctUINT32 address; + gctUINT32 link; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x FetchAddress=0x%x FetchSize=%lu " + "*Bytes=%lu", + Hardware, Logical, FetchAddress, FetchSize, + gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT((Logical == gcvNULL) || (Bytes != gcvNULL)); + + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Convert logical address to hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, FetchAddress, &address)); + + gcmkONERROR( + gckOS_WriteMemory(Hardware->os, logical + 1, address)); + + /* Make sure the address got written before the LINK command. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical + 1)); + + /* Compute number of 64-byte aligned bytes to fetch. */ + bytes = gcmALIGN(address + FetchSize, 64) - address; + + /* Append LINK(bytes / 8), FetchAddress. */ + link = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (bytes >> 3) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + gcmkONERROR( + gckOS_WriteMemory(Hardware->os, logical, link)); + + /* Memory barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, logical)); + } + + if (Bytes != gcvNULL) + { + /* Return number of bytes required by the LINK command. */ + *Bytes = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_UpdateQueueTail +** +** Update the tail of the command queue. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the start of the command queue. +** +** gctUINT32 Offset +** Offset into the command queue of the tail (last command). +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x Offset=0x%08x", + Hardware, Logical, Offset); + + /* Verify the hardware. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Force a barrier. */ + gcmkONERROR( + gckOS_MemoryBarrier(Hardware->os, Logical)); + + /* Notify gckKERNEL object of change. */ + gcmkONERROR( + gckKERNEL_Notify(Hardware->kernel, + gcvNOTIFY_COMMAND_QUEUE, + gcvFALSE)); + + if (status == gcvSTATUS_CHIP_NOT_READY) + { + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertLogical +** +** Convert a logical system address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Convert logical address into a physical address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Hardware->os, Logical, &address)); + + /* Return hardware specific address. */ + *Address = (Hardware->mmuVersion == 0) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) + : address; + + /* Success. */ + gcmkFOOTER_ARG("*Address=0x%08x", *Address); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_ConvertPhysical +** +** Convert a physical address into a hardware specific address. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctPHYS_ADDR Physical +** Physical address to convert. +** +** gctUINT32* Address +** Return hardware specific address. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ) +{ + gctUINT32 address; + + gcmkHEADER_ARG("Hardware=0x%x Physical=0x%x", Hardware, Physical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + address = gcmPTR2INT(Physical); + + /* Return hardware specific address. */ + *Address = (Hardware->mmuVersion == 0) + ? ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (address) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) + : address; + + /* Return the status. */ + gcmkFOOTER_ARG("*Address=0x%08x", *Address); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_Interrupt +** +** Process an interrupt. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gctBOOL InterruptValid +** If gcvTRUE, this function will read the interrupt acknowledge +** register, stores the data, and return whether or not the interrupt +** is ours or not. If gcvFALSE, this functions will read the interrupt +** acknowledge register and combine it with any stored value to handle +** the event notifications. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ) +{ + gckEVENT eventObj; + gctUINT32 data; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x InterruptValid=%d", Hardware, InterruptValid); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Extract gckEVENT object. */ + eventObj = Hardware->kernel->eventObj; + gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT); + + if (InterruptValid) + { + /* Read AQIntrAcknowledge register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00010, + &data)); + + if (data & 0x80000000) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_HARDWARE, "AXI BUS ERROR"); + } + + if (data == 0) + { + /* Not our interrupt. */ + status = gcvSTATUS_NOT_OUR_INTERRUPT; + } + else + { + /* Inform gckEVENT of the interrupt. */ + status = gckEVENT_Interrupt(eventObj, data & 0x7FFFFFFF); + } + } + else + { + /* Handle events. */ + status = gckEVENT_Notify(eventObj, 0); + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_QueryCommandBuffer +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * Alignment +** Pointer to a variable receiving the alignment for each command. +** +** gctSIZE_T * ReservedHead +** Pointer to a variable receiving the number of reserved bytes at the +** head of each command buffer. +** +** gctSIZE_T * ReservedTail +** Pointer to a variable receiving the number of bytes reserved at the +** tail of each command buffer. +*/ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Alignment != gcvNULL) + { + /* Align every 8 bytes. */ + *Alignment = 8; + } + + if (ReservedHead != gcvNULL) + { + /* Reserve space for SelectPipe(). */ + *ReservedHead = 32; + } + + if (ReservedTail != gcvNULL) + { + /* Reserve space for Link(). */ + *ReservedTail = 8; + } + + /* Success. */ + gcmkFOOTER_ARG("*Alignment=%lu *ReservedHead=%lu *ReservedTail=%lu", + gcmOPT_VALUE(Alignment), gcmOPT_VALUE(ReservedHead), + gcmOPT_VALUE(ReservedTail)); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHARDWARE_QuerySystemMemory +** +** Query the command buffer alignment and number of reserved bytes. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** gctSIZE_T * SystemSize +** Pointer to a variable that receives the maximum size of the system +** memory. +** +** gctUINT32 * SystemBaseAddress +** Poinetr to a variable that receives the base address for system +** memory. +*/ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (SystemSize != gcvNULL) + { + /* Maximum system memory can be 2GB. */ + *SystemSize = 1U << 31; + } + + if (SystemBaseAddress != gcvNULL) + { + /* Set system memory base address. */ + *SystemBaseAddress = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))); + } + + /* Success. */ + gcmkFOOTER_ARG("*SystemSize=%lu *SystemBaseAddress=%lu", + gcmOPT_VALUE(SystemSize), gcmOPT_VALUE(SystemBaseAddress)); + return gcvSTATUS_OK; +} + +#if !defined(VIVANTE_NO_3D) +/******************************************************************************* +** +** gckHARDWARE_QueryShaderCaps +** +** Query the shader capabilities. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT * VertexUniforms +** Pointer to a variable receiving the number of uniforms in the vertex +** shader. +** +** gctUINT * FragmentUniforms +** Pointer to a variable receiving the number of uniforms in the +** fragment shader. +** +** gctUINT * Varyings +** Pointer to a variable receiving the maimum number of varyings. +*/ +gceSTATUS +gckHARDWARE_QueryShaderCaps( + IN gckHARDWARE Hardware, + OUT gctUINT * VertexUniforms, + OUT gctUINT * FragmentUniforms, + OUT gctUINT * Varyings + ) +{ + gcmkHEADER_ARG("Hardware=0x%x VertexUniforms=0x%x " + "FragmentUniforms=0x%x Varyings=0x%x", + Hardware, VertexUniforms, + FragmentUniforms, Varyings); + + if (VertexUniforms != gcvNULL) + { + /* Return the vs shader const count. */ + if (Hardware->identity.chipModel < gcv4000) + { + *VertexUniforms = 168; + } + else + { + *VertexUniforms = 256; + } + } + + if (FragmentUniforms != gcvNULL) + { + /* Return the ps shader const count. */ + if (Hardware->identity.chipModel < gcv4000) + { + *FragmentUniforms = 64; + } + else + { + *FragmentUniforms = 256; + } + } + + if (Varyings != gcvNULL) + { + /* Return the shader varyings count. */ + if (((((gctUINT32) (Hardware->identity.chipMinorFeatures1)) >> (0 ? 23:23) & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 23:23) - (0 ? 23:23) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:23) - (0 ? 23:23) + 1)))))))) + { + *Varyings = 12; + } + else + { + *Varyings = 8; + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} +#endif + +/******************************************************************************* +** +** gckHARDWARE_SetMMU +** +** Set the page table base address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctPOINTER Logical +** Logical address of the page table. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ) +{ + gceSTATUS status; + gctUINT32 address = 0; + gctUINT32 baseAddress; + + gcmkHEADER_ARG("Hardware=0x%x Logical=0x%x", Hardware, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Convert the logical address into an hardware address. */ + gcmkONERROR( + gckHARDWARE_ConvertLogical(Hardware, Logical, &address)); + + /* Also get the base address - we need a real physical address. */ + gcmkONERROR( + gckOS_GetBaseAddress(Hardware->os, &baseAddress)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Setting page table to 0x%08X", + address + baseAddress); + + /* Write the AQMemoryFePageTable register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00400, + address + baseAddress)); + + /* Write the AQMemoryRaPageTable register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00410, + address + baseAddress)); + + /* Write the AQMemoryTxPageTable register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00404, + address + baseAddress)); + + + /* Write the AQMemoryPePageTable register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00408, + address + baseAddress)); + + /* Write the AQMemoryPezPageTable register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0040C, + address + baseAddress)); + + /* Return the status. */ + gcmkFOOTER_NO(); + return status; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_FlushMMU +** +** Flush the page table. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gckCOMMAND command; + gctUINT32_PTR buffer; + gctSIZE_T bufferSize; + gctBOOL commitEntered = gcvFALSE; + gctPOINTER pointer = gcvNULL; + gctUINT32 flushSize; + gctUINT32 count; + gctUINT32 physical; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Verify the gckCOMMAND object pointer. */ + command = Hardware->kernel->command; + + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(command, gcvFALSE)); + commitEntered = gcvTRUE; + + /* Flush the memory controller. */ + if (Hardware->mmuVersion == 0) + { + gcmkONERROR(gckCOMMAND_Reserve( + command, 8, &pointer, &bufferSize + )); + + buffer = (gctUINT32_PTR) pointer; + + buffer[0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E04) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[1] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))); + + gcmkONERROR(gckCOMMAND_Execute(command, 8)); + } + else + { + flushSize = 16 * 4; + + gcmkONERROR(gckCOMMAND_Reserve( + command, flushSize, &pointer, &bufferSize + )); + + buffer = (gctUINT32_PTR) pointer; + + count = (bufferSize - flushSize + 7) >> 3; + + gcmkONERROR(gckOS_GetPhysicalAddress(command->os, buffer, &physical)); + + /* Flush cache. */ + buffer[0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[1] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1))))))) << (0 ? 5:5))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1))))))) << (0 ? 6:6))); + + /* Arm the PE-FE Semaphore. */ + buffer[2] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[3] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* STALL FE until PE is done flushing. */ + buffer[4] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + buffer[5] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* LINK to next slot to flush FE FIFO. */ + buffer[6] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[7] + = physical + 8 * gcmSIZEOF(gctUINT32); + + /* Flush MMU cache. */ + buffer[8] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[9] + = (((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1))))))) << (0 ? 4:4))) & ((((gctUINT32) (~0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1))))))) << (0 ? 7:7))) ); + + /* Arm the PE-FE Semaphore. */ + buffer[10] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E02) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[11] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* STALL FE until PE is done flushing. */ + buffer[12] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x09 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))); + + buffer[13] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 4:0) - (0 ? 4:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:0) - (0 ? 4:0) + 1))))))) << (0 ? 4:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))) | (((gctUINT32) (0x07 & ((gctUINT32) ((((1 ? 12:8) - (0 ? 12:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:8) - (0 ? 12:8) + 1))))))) << (0 ? 12:8))); + + /* LINK to next slot to flush FE FIFO. */ + buffer[14] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x08 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (count) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))); + + buffer[15] + = physical + flushSize; + + gcmkONERROR(gckCOMMAND_Execute(command, flushSize)); + } + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(command, gcvFALSE)); + commitEntered = gcvFALSE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Hardware->kernel->command, + gcvFALSE)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_SetMMUv2 +** +** Set the page table base address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_SetMMUv2( + IN gckHARDWARE Hardware, + IN gctBOOL Enable, + IN gctPOINTER MtlbAddress, + IN gceMMU_MODE Mode, + IN gctPOINTER SafeAddress, + IN gctBOOL FromPower + ) +{ + gceSTATUS status; + gctUINT32 config, address; + gckCOMMAND command; + gctUINT32_PTR buffer; + gctSIZE_T bufferSize; + gctBOOL commitEntered = gcvFALSE; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Hardware=0x%x Enable=%d", Hardware, Enable); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Convert logical address into physical address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Hardware->os, MtlbAddress, &config)); + + gcmkONERROR( + gckOS_GetPhysicalAddress(Hardware->os, SafeAddress, &address)); + + if (address & 0x3F) + { + gcmkONERROR(gcvSTATUS_NOT_ALIGNED); + } + + switch (Mode) + { + case gcvMMU_MODE_1K: + if (config & 0x3FF) + { + gcmkONERROR(gcvSTATUS_NOT_ALIGNED); + } + + config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + + break; + + case gcvMMU_MODE_4K: + if (config & 0xFFF) + { + gcmkONERROR(gcvSTATUS_NOT_ALIGNED); + } + + config |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x0 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + + break; + + default: + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Verify the gckCOMMAND object pointer. */ + command = Hardware->kernel->command; + + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower)); + commitEntered = gcvTRUE; + + gcmkONERROR(gckCOMMAND_Reserve( + command, 16, &pointer, &bufferSize + )); + + buffer = pointer; + + buffer[0] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0061) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[1] = config; + + buffer[2] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0060) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + buffer[3] = address; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Setup MMU: config=%08x, Safe Address=%08x\n.", config, address); + + gcmkONERROR(gckCOMMAND_Execute(command, 16)); + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower)); + commitEntered = gcvFALSE; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "call gckCOMMAND_Stall to make sure the config is done.\n "); + + gcmkONERROR(gckCOMMAND_Stall(command, FromPower)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Enable MMU through GCREG_MMU_CONTROL."); + + /* Enable MMU. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0018C, + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (Enable) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))))); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "call gckCOMMAND_Stall to check MMU available.\n"); + + gcmkONERROR(gckCOMMAND_Stall(command, FromPower)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "The MMU is available.\n"); + + /* Return the status. */ + gcmkFOOTER_NO(); + return status; + +OnError: + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Hardware->kernel->command, + gcvFALSE)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_BuildVirtualAddress +** +** Build a virtual address. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gctUINT32 Index +** Index into page table. +** +** gctUINT32 Offset +** Offset into page. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable receiving te hardware address. +*/ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ) +{ + gcmkHEADER_ARG("Hardware=0x%x Index=%u Offset=%u", Hardware, Index, Offset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Build virtual address. */ + *Address = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 31:31) - (0 ? 31:31) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:31) - (0 ? 31:31) + 1))))))) << (0 ? 31:31))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))) | (((gctUINT32) ((gctUINT32) (Offset | (Index << 12)) & ((gctUINT32) ((((1 ? 30:0) - (0 ? 30:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 30:0) - (0 ? 30:0) + 1))))))) << (0 ? 30:0))); + + /* Success. */ + gcmkFOOTER_ARG("*Address=0x%08x", *Address); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ) +{ + gceSTATUS status; + gctUINT32 idle = 0; + gctINT retry, poll, pollCount; + + gcmkHEADER_ARG("Hardware=0x%x Wait=%d", Hardware, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + + /* If we have to wait, try 100 polls per millisecond. */ + pollCount = Wait ? 100 : 1; + + /* At most, try for 1 second. */ + for (retry = 0; retry < 1000; ++retry) + { + /* If we have to wait, try 100 polls per millisecond. */ + for (poll = pollCount; poll > 0; --poll) + { + /* Read register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle)); + + /* See if we have to wait for FE idle. */ + if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* FE is idle. */ + break; + } + } + + /* Check if we need to wait for FE and FE is busy. */ + if (Wait && !(((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + /* Wait a little. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "%s: Waiting for idle: 0x%08X", + __FUNCTION__, idle); + + gcmkVERIFY_OK(gckOS_Delay(Hardware->os, 1)); + } + else + { + break; + } + } + + /* Return idle to caller. */ + *Data = idle; + + /* Success. */ + gcmkFOOTER_ARG("*Data=0x%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ) +{ + gctUINT32 pipe; + gctUINT32 flush = 0; + gctUINT32_PTR logical = (gctUINT32_PTR) Logical; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Flush=0x%x Logical=0x%x *Bytes=%lu", + Hardware, Flush, Logical, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get current pipe. */ + pipe = Hardware->kernel->command->pipeSelect; + + /* Flush 3D color cache. */ + if ((Flush & gcvFLUSH_COLOR) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))); + } + + /* Flush 3D depth cache. */ + if ((Flush & gcvFLUSH_DEPTH) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))); + } + + /* Flush 3D texture cache. */ + if ((Flush & gcvFLUSH_TEXTURE) && (pipe == 0x0)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1))))))) << (0 ? 2:2))); + } + + /* Flush 2D cache. */ + if ((Flush & gcvFLUSH_2D) && (pipe == 0x1)) + { + flush |= ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1))))))) << (0 ? 3:3))); + } + + /* See if there is a valid flush. */ + if (flush == 0) + { + if (Bytes != gcvNULL) + { + /* No bytes required. */ + *Bytes = 0; + } + } + + else + { + /* Copy to command queue. */ + if (Logical != gcvNULL) + { + if (*Bytes < 8) + { + /* Command queue too small. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + + /* Append LOAD_STATE to AQFlush. */ + logical[0] = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) | (((gctUINT32) (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1))))))) << (0 ? 31:27))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) | (((gctUINT32) ((gctUINT32) (0x0E03) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1))))))) << (0 ? 15:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 25:16) - (0 ? 25:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 25:16) - (0 ? 25:16) + 1))))))) << (0 ? 25:16))); + + logical[1] = flush; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "0x%x: FLUSH 0x%x", logical, flush); + } + + if (Bytes != gcvNULL) + { + /* 8 bytes required. */ + *Bytes = 8; + } + } + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ) +{ +#ifndef VIVANTE_NO_3D + gctUINT32 debug; + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x Enable=%d Compression=%d", + Hardware, Enable, Compression); + + /* Only process if fast clear is available. */ + if ((((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) )) + { + if (Enable == -1) + { + /* Determine automatic value for fast clear. */ + Enable = ((Hardware->identity.chipModel != gcv500) + || (Hardware->identity.chipRevision >= 3) + ) ? 1 : 0; + } + + if (Compression == -1) + { + /* Determine automatic value for compression. */ + Compression = Enable + & (((((gctUINT32) (Hardware->identity.chipFeatures)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ); + } + + /* Read AQMemoryDebug register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &debug)); + + /* Set fast clear bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))) | (((gctUINT32) ((gctUINT32) (Enable == 0) & ((gctUINT32) ((((1 ? 20:20) - (0 ? 20:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:20) - (0 ? 20:20) + 1))))))) << (0 ? 20:20))); + + /* Set compression bypass. */ + debug = ((((gctUINT32) (debug)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))) | (((gctUINT32) ((gctUINT32) (Compression == 0) & ((gctUINT32) ((((1 ? 21:21) - (0 ? 21:21) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 21:21) - (0 ? 21:21) + 1))))))) << (0 ? 21:21))); + + /* Write back AQMemoryDebug register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00414, + debug)); + + /* Store fast clear and comprersison flags. */ + Hardware->allowFastClear = Enable; + Hardware->allowCompression = Compression; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "FastClear=%d Compression=%d", Enable, Compression); + } + + /* Special patch for 0x320 0x5220. */ + if (Hardware->identity.chipRevision == 0x5220 && Hardware->identity.chipModel == gcv320) + { + gctUINT32 debug; + + /* Read AQMemoryDebug register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00414, &debug)); + + debug |= 8; + + /* Write back AQMemoryDebug register. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00414, + debug)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + return gcvSTATUS_OK; +#endif +} + +typedef enum +{ + gcvPOWER_FLAG_INITIALIZE = 1 << 0, + gcvPOWER_FLAG_STALL = 1 << 1, + gcvPOWER_FLAG_STOP = 1 << 2, + gcvPOWER_FLAG_START = 1 << 3, + gcvPOWER_FLAG_RELEASE = 1 << 4, + gcvPOWER_FLAG_DELAY = 1 << 5, + gcvPOWER_FLAG_SAVE = 1 << 6, + gcvPOWER_FLAG_ACQUIRE = 1 << 7, + gcvPOWER_FLAG_POWER_OFF = 1 << 8, + gcvPOWER_FLAG_CLOCK_OFF = 1 << 9, + gcvPOWER_FLAG_CLOCK_ON = 1 << 10, +} +gcePOWER_FLAGS; + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) && gcdPOWER_MANAGEMENT +static gctCONST_STRING +_PowerEnum(gceCHIPPOWERSTATE State) +{ + const gctCONST_STRING states[] = + { + gcmSTRING(gcvPOWER_ON), + gcmSTRING(gcvPOWER_OFF), + gcmSTRING(gcvPOWER_IDLE), + gcmSTRING(gcvPOWER_SUSPEND), + gcmSTRING(gcvPOWER_SUSPEND_ATPOWERON), + gcmSTRING(gcvPOWER_OFF_ATPOWERON), + gcmSTRING(gcvPOWER_IDLE_BROADCAST), + gcmSTRING(gcvPOWER_SUSPEND_BROADCAST), + gcmSTRING(gcvPOWER_OFF_BROADCAST), + gcmSTRING(gcvPOWER_OFF_RECOVERY), + gcmSTRING(gcvPOWER_ON_AUTO) + }; + + if ((State >= gcvPOWER_ON) && (State <= gcvPOWER_ON_AUTO)) + { + return states[State - gcvPOWER_ON]; + } + + return "unknown"; +} +#endif + +/******************************************************************************* +** +** gckHARDWARE_SetPowerManagementState +** +** Set GPU to a specified power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ) +{ +#if gcdPOWER_MANAGEMENT + gceSTATUS status; + gckCOMMAND command = gcvNULL; + gckOS os; + gctUINT flag, clock; + gctPOINTER buffer; + gctSIZE_T bytes, requested; + gctBOOL acquired = gcvFALSE; + gctBOOL mutexAcquired = gcvFALSE; + gctBOOL stall = gcvTRUE; + gctBOOL broadcast = gcvFALSE; +#if gcdPOWEROFF_TIMEOUT + gctBOOL timeout = gcvFALSE; + gctBOOL isAfter = gcvFALSE; + gctUINT32 currentTime; +#endif + gctUINT32 process, thread; + gctBOOL commitEntered = gcvFALSE; +#if gcdENABLE_PROFILING + gctUINT64 time, freq, mutexTime, onTime, stallTime, stopTime, delayTime, + initTime, offTime, startTime, totalTime; +#endif + gctBOOL global = gcvFALSE; + gctBOOL globalAcquired = gcvFALSE; + gctBOOL configMmu = gcvFALSE; + + /* State transition flags. */ + static const gctUINT flags[4][4] = + { + /* gcvPOWER_ON */ + { /* ON */ 0, + /* OFF */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_POWER_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL, + /* SUSPEND */ gcvPOWER_FLAG_ACQUIRE | + gcvPOWER_FLAG_STALL | + gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_OFF */ + { /* ON */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY, + /* OFF */ 0, + /* IDLE */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY, + /* SUSPEND */ gcvPOWER_FLAG_INITIALIZE | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_IDLE */ + { /* ON */ gcvPOWER_FLAG_RELEASE, + /* OFF */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_POWER_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ 0, + /* SUSPEND */ gcvPOWER_FLAG_STOP | + gcvPOWER_FLAG_CLOCK_OFF, + }, + + /* gcvPOWER_SUSPEND */ + { /* ON */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_RELEASE | + gcvPOWER_FLAG_DELAY | + gcvPOWER_FLAG_CLOCK_ON, + /* OFF */ gcvPOWER_FLAG_SAVE | + gcvPOWER_FLAG_POWER_OFF | + gcvPOWER_FLAG_CLOCK_OFF, + /* IDLE */ gcvPOWER_FLAG_START | + gcvPOWER_FLAG_DELAY | + gcvPOWER_FLAG_CLOCK_ON, + /* SUSPEND */ 0, + }, + }; + + /* Clocks. */ + static const gctUINT clocks[4] = + { + /* gcvPOWER_ON */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (64) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_OFF */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_IDLE */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + + /* gcvPOWER_SUSPEND */ + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1))))))) << (0 ? 1:1))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:2) - (0 ? 8:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:2) - (0 ? 8:2) + 1))))))) << (0 ? 8:2))) | + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))), + }; + + gcmkHEADER_ARG("Hardware=0x%x State=%d", Hardware, State); +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Switching to power state %d(%s)", + State, _PowerEnum(State)); +#endif + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Get the gckOS object pointer. */ + os = Hardware->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Get the gckCOMMAND object pointer. */ + gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL); + command = Hardware->kernel->command; + gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); + + /* Start profiler. */ + gcmkPROFILE_INIT(freq, time); + + /* Convert the broadcast power state. */ + switch (State) + { + case gcvPOWER_SUSPEND_ATPOWERON: + /* Convert to SUSPEND and don't wait for STALL. */ + State = gcvPOWER_SUSPEND; + stall = gcvFALSE; + break; + + case gcvPOWER_OFF_ATPOWERON: + /* Convert to OFF and don't wait for STALL. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + break; + + case gcvPOWER_IDLE_BROADCAST: + /* Convert to IDLE and note we are inside broadcast. */ + State = gcvPOWER_IDLE; + broadcast = gcvTRUE; + break; + + case gcvPOWER_SUSPEND_BROADCAST: + /* Convert to SUSPEND and note we are inside broadcast. */ + State = gcvPOWER_SUSPEND; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_BROADCAST: + /* Convert to OFF and note we are inside broadcast. */ + State = gcvPOWER_OFF; + broadcast = gcvTRUE; + break; + + case gcvPOWER_OFF_RECOVERY: + /* Convert to OFF and note we are inside recovery. */ + State = gcvPOWER_OFF; + stall = gcvFALSE; + broadcast = gcvTRUE; + break; + + case gcvPOWER_ON_AUTO: + /* Convert to ON and note we are inside recovery. */ + State = gcvPOWER_ON; + break; + + case gcvPOWER_ON: + case gcvPOWER_IDLE: + case gcvPOWER_SUSPEND: + case gcvPOWER_OFF: + /* Mark as global power management. */ + global = gcvTRUE; + break; + +#if gcdPOWEROFF_TIMEOUT + case gcvPOWER_OFF_TIMEOUT: + /* Convert to OFF and note we are inside broadcast. */ + State = gcvPOWER_OFF; + broadcast = gcvTRUE; + /* Check time out */ + timeout = gcvTRUE; + break; +#endif + + default: + break; + } + + /* Get current process and thread IDs. */ + gcmkONERROR(gckOS_GetProcessID(&process)); + gcmkONERROR(gckOS_GetThreadID(&thread)); + + if (broadcast) + { + /* Try to acquire the power mutex. */ + status = gckOS_AcquireMutex(os, Hardware->powerMutex, 0); + + if (status == gcvSTATUS_TIMEOUT) + { + /* Check if we already own this mutex. */ + if ((Hardware->powerProcess == process) + && (Hardware->powerThread == thread) + ) + { + /* Bail out on recursive power management. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + else if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND) + { + /* Called from IST, + ** so waiting here will cause deadlock, + ** if lock holder call gckCOMMAND_Stall() */ + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, + Hardware->powerMutex, + gcvINFINITE)); + } + } + } + else + { + /* Acquire the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Hardware->powerMutex, gcvINFINITE)); + } + + /* Get time until mtuex acquired. */ + gcmkPROFILE_QUERY(time, mutexTime); + + Hardware->powerProcess = process; + Hardware->powerThread = thread; + mutexAcquired = gcvTRUE; + + /* Grab control flags and clock. */ + flag = flags[Hardware->chipPowerState][State]; + clock = clocks[State]; + +#if gcdPOWEROFF_TIMEOUT + if (timeout) + { + gcmkONERROR(gckOS_GetTicks(¤tTime)); + + gcmkONERROR( + gckOS_TicksAfter(Hardware->powerOffTime, currentTime, &isAfter)); + + /* powerOffTime is pushed forward, give up.*/ + if (isAfter + /* Expect a transition start from IDLE or SUSPEND. */ + || (Hardware->chipPowerState == gcvPOWER_ON) + || (Hardware->chipPowerState == gcvPOWER_OFF) + ) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* No need to do anything. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Power Off GPU[%d] at %u [supposed to be at %u]", + Hardware->core, currentTime, Hardware->powerOffTime); + } +#endif + + if (flag == 0) + { + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* No need to do anything. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* If this is an internal power management, we have to check if we can grab + ** the global power semaphore. If we cannot, we have to wait until the + ** external world changes power management. */ + if (!global) + { + /* Try to acquire the global semaphore. */ + status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); + if (status == gcvSTATUS_TIMEOUT) + { + if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND) + { + /* Called from thread routine which should NEVER sleep.*/ + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + + /* Release the power mutex. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Releasing the power mutex."); + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + mutexAcquired = gcvFALSE; + + /* Wait for the semaphore. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Waiting for global semaphore."); + gcmkONERROR(gckOS_AcquireSemaphore(os, Hardware->globalSemaphore)); + globalAcquired = gcvTRUE; + + /* Acquire the power mutex. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "Reacquiring the power mutex."); + gcmkONERROR(gckOS_AcquireMutex(os, + Hardware->powerMutex, + gcvINFINITE)); + mutexAcquired = gcvTRUE; + + /* chipPowerState may be changed by external world during the time + ** we give up powerMutex, so updating flag now is necessary. */ + flag = flags[Hardware->chipPowerState][State]; + + if (flag == 0) + { + gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); + globalAcquired = gcvFALSE; + + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + mutexAcquired = gcvFALSE; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + } + else + { + /* Error. */ + gcmkONERROR(status); + } + + /* Release the global semaphore again. */ + gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); + globalAcquired = gcvFALSE; + } + else + { + if (State == gcvPOWER_OFF || State == gcvPOWER_SUSPEND || State == gcvPOWER_IDLE) + { + /* Acquire the global semaphore if it has not been acquired. */ + status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); + if (status == gcvSTATUS_OK) + { + globalAcquired = gcvTRUE; + } + else if (status != gcvSTATUS_TIMEOUT) + { + /* Other errors. */ + gcmkONERROR(status); + } + /* Ignore gcvSTATUS_TIMEOUT and leave globalAcquired as gcvFALSE. + ** gcvSTATUS_TIMEOUT means global semaphore has already + ** been acquired before this operation, so even if we fail, + ** we should not release it in our error handling. It should be + ** released by the next successful global gcvPOWER_ON. */ + } + + /* Global power management can't be aborted, so sync with + ** proceeding last commit. */ + if (flag & gcvPOWER_FLAG_ACQUIRE) + { + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); + acquired = gcvTRUE; + + /* avoid acquiring again. */ + flag &= ~gcvPOWER_FLAG_ACQUIRE; + } + } + + if (flag & (gcvPOWER_FLAG_INITIALIZE | gcvPOWER_FLAG_CLOCK_ON)) + { + /* Turn on the power. */ + gcmkONERROR(gckOS_SetGPUPower(os, gcvTRUE, gcvTRUE)); + + /* Mark clock and power as enabled. */ + Hardware->clockState = gcvTRUE; + Hardware->powerState = gcvTRUE; + } + + /* Get time until powered on. */ + gcmkPROFILE_QUERY(time, onTime); + + if ((flag & gcvPOWER_FLAG_STALL) && stall) + { + gctBOOL idle; + gctINT32 atomValue; + + /* For global operation, all pending commits have already been + ** blocked by globalSemaphore or powerSemaphore.*/ + if (!global) + { + /* Check commit atom. */ + gcmkONERROR(gckOS_AtomGet(os, command->atomCommit, &atomValue)); + + if (atomValue > 0) + { + /* Commits are pending - abort power management. */ + status = broadcast ? gcvSTATUS_CHIP_NOT_READY + : gcvSTATUS_MORE_DATA; + goto OnError; + } + } + + if (broadcast) + { + /* Check for idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Hardware, &idle)); + + if (!idle) + { + status = gcvSTATUS_CHIP_NOT_READY; + goto OnError; + } + } + + else + { + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(command, gcvTRUE)); + commitEntered = gcvTRUE; + + /* Get the size of the flush command. */ + gcmkONERROR(gckHARDWARE_Flush(Hardware, + gcvFLUSH_ALL, + gcvNULL, + &requested)); + + /* Reserve space in the command queue. */ + gcmkONERROR(gckCOMMAND_Reserve(command, + requested, + &buffer, + &bytes)); + + /* Append a flush. */ + gcmkONERROR(gckHARDWARE_Flush( + Hardware, gcvFLUSH_ALL, buffer, &bytes + )); + + /* Execute the command queue. */ + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(command, gcvTRUE)); + commitEntered = gcvFALSE; + + /* Wait to finish all commands. */ + gcmkONERROR(gckCOMMAND_Stall(command, gcvTRUE)); + } + } + + /* Get time until stalled. */ + gcmkPROFILE_QUERY(time, stallTime); + + if (flag & gcvPOWER_FLAG_ACQUIRE) + { + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(os, command->powerSemaphore)); + acquired = gcvTRUE; + } + + if (flag & gcvPOWER_FLAG_STOP) + { + /* Stop the command parser. */ + gcmkONERROR(gckCOMMAND_Stop(command, gcvFALSE)); + + /* Stop the Isr. */ + gcmkONERROR(Hardware->stopIsr(Hardware->isrContext)); + } + + /* Get time until stopped. */ + gcmkPROFILE_QUERY(time, stopTime); + + /* Only process this when hardware is enabled. */ + if (Hardware->clockState && Hardware->powerState) + { + if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF)) + { + if (Hardware->identity.chipModel == gcv4000 + && Hardware->identity.chipRevision == 0x5208) + { + clock &= ~2U; + } + } + + /* Write the clock control register. */ + gcmkONERROR(gckOS_WriteRegisterEx(os, + Hardware->core, + 0x00000, + clock)); + + /* Done loading the frequency scaler. */ + gcmkONERROR(gckOS_WriteRegisterEx(os, + Hardware->core, + 0x00000, + ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); + } + + if (flag & gcvPOWER_FLAG_DELAY) + { + /* Wait for the specified amount of time to settle coming back from + ** power-off or suspend state. */ + gcmkONERROR(gckOS_Delay(os, gcdPOWER_CONTROL_DELAY)); + } + + /* Get time until delayed. */ + gcmkPROFILE_QUERY(time, delayTime); + + if (flag & gcvPOWER_FLAG_INITIALIZE) + { + /* Initialize hardware. */ + gcmkONERROR(gckHARDWARE_InitializeHardware(Hardware)); + + gcmkONERROR(gckHARDWARE_SetFastClear(Hardware, + Hardware->allowFastClear, + Hardware->allowCompression)); + + /* Force the command queue to reload the next context. */ + command->currContext = gcvNULL; + + /* Need to config mmu after command start. */ + configMmu = gcvTRUE; + } + + /* Get time until initialized. */ + gcmkPROFILE_QUERY(time, initTime); + + if (flag & (gcvPOWER_FLAG_POWER_OFF | gcvPOWER_FLAG_CLOCK_OFF)) + { + /* Turn off the GPU power. */ + gcmkONERROR( + gckOS_SetGPUPower(os, + (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE + : gcvTRUE, + (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE + : gcvTRUE)); + + /* Save current hardware power and clock states. */ + Hardware->clockState = (flag & gcvPOWER_FLAG_CLOCK_OFF) ? gcvFALSE + : gcvTRUE; + Hardware->powerState = (flag & gcvPOWER_FLAG_POWER_OFF) ? gcvFALSE + : gcvTRUE; + } + + /* Get time until off. */ + gcmkPROFILE_QUERY(time, offTime); + + if (flag & gcvPOWER_FLAG_START) + { + /* Start the command processor. */ + gcmkONERROR(gckCOMMAND_Start(command)); + + /* Start the Isr. */ + gcmkONERROR(Hardware->startIsr(Hardware->isrContext)); + + /* Set NEW MMU. */ + if (Hardware->mmuVersion != 0 && configMmu) + { + gcmkONERROR( + gckHARDWARE_SetMMUv2( + Hardware, + gcvTRUE, + Hardware->kernel->mmu->mtlbLogical, + gcvMMU_MODE_4K, + (gctUINT8_PTR)Hardware->kernel->mmu->mtlbLogical + gcdMMU_MTLB_SIZE, + gcvTRUE + )); + } + } + + /* Get time until started. */ + gcmkPROFILE_QUERY(time, startTime); + + if (flag & gcvPOWER_FLAG_RELEASE) + { + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(os, command->powerSemaphore)); + acquired = gcvFALSE; + + if (global) + { + /* Verify global semaphore has been acquired already before + ** we release it. + ** If it was acquired, gckOS_TryAcquireSemaphore will return + ** gcvSTATUS_TIMEOUT and we release it. Otherwise, global + ** semaphore will be acquried now, but it still is released + ** immediately. */ + status = gckOS_TryAcquireSemaphore(os, Hardware->globalSemaphore); + if (status != gcvSTATUS_TIMEOUT) + { + gcmkONERROR(status); + } + + /* Release the global semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(os, Hardware->globalSemaphore)); + globalAcquired = gcvFALSE; + } + } + + /* Save the new power state. */ + Hardware->chipPowerState = State; + +#if gcdPOWEROFF_TIMEOUT + /* Reset power off time */ + gcmkONERROR(gckOS_GetTicks(¤tTime)); + + Hardware->powerOffTime = currentTime + Hardware->powerOffTimeout; + + if (State == gcvPOWER_IDLE || State == gcvPOWER_SUSPEND) + { + /* Start a timer to power off GPU when GPU enters IDLE or SUSPEND. */ + gcmkVERIFY_OK(gckOS_StartTimer(os, + Hardware->powerOffTimer, + Hardware->powerOffTimeout)); + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, "Cancel powerOfftimer"); + + /* Cancel running timer when GPU enters ON or OFF. */ + gcmkVERIFY_OK(gckOS_StopTimer(os, Hardware->powerOffTimer)); + } +#endif + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(os, Hardware->powerMutex)); + + /* Get total time. */ + gcmkPROFILE_QUERY(time, totalTime); +#if gcdENABLE_PROFILING + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + "PROF(%llu): mutex:%llu on:%llu stall:%llu stop:%llu", + freq, mutexTime, onTime, stallTime, stopTime); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HARDWARE, + " delay:%llu init:%llu off:%llu start:%llu total:%llu", + delayTime, initTime, offTime, startTime, totalTime); +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, gcvTRUE)); + } + + if (acquired) + { + /* Release semaphore. */ + gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os, + command->powerSemaphore)); + } + + if (globalAcquired) + { + gcmkVERIFY_OK(gckOS_ReleaseSemaphore(Hardware->os, + Hardware->globalSemaphore)); + } + + if (mutexAcquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Hardware->os, Hardware->powerMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +#else /* gcdPOWER_MANAGEMENT */ + /* Do nothing */ + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckHARDWARE_QueryPowerManagementState +** +** Get GPU power state. +** +** INPUT: +** +** gckHARDWARE Harwdare +** Pointer to an gckHARDWARE object. +** +** gceCHIPPOWERSTATE* State +** Power State. +** +*/ +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(State != gcvNULL); + + /* Return the statue. */ + *State = Hardware->chipPowerState; + + /* Success. */ + gcmkFOOTER_ARG("*State=%d", *State); + return gcvSTATUS_OK; +} + +#if gcdPOWEROFF_TIMEOUT +gceSTATUS +gckHARDWARE_SetPowerOffTimeout( + IN gckHARDWARE Hardware, + IN gctUINT32 Timeout +) +{ + gcmkHEADER_ARG("Hardware=0x%x Timeout=%d", Hardware, Timeout); + + Hardware->powerOffTimeout = Timeout; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + + +gceSTATUS +gckHARDWARE_QueryPowerOffTimeout( + IN gckHARDWARE Hardware, + OUT gctUINT32* Timeout +) +{ + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + *Timeout = Hardware->powerOffTimeout; + + gcmkFOOTER_ARG("*Timeout=%d", *Timeout); + return gcvSTATUS_OK; +} +#endif + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ) +{ + gceSTATUS status; + gctUINT32 idle, address; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(IsIdle != gcvNULL); + + /* We are idle when the power is not ON. */ + if (Hardware->chipPowerState != gcvPOWER_ON) + { + *IsIdle = gcvTRUE; + } + + else + { + /* Read idle register. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00004, &idle)); + + /* Pipe must be idle. */ + if (((((((gctUINT32) (idle)) >> (0 ? 1:1)) & ((gctUINT32) ((((1 ? 1:1) - (0 ? 1:1) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:1) - (0 ? 1:1) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 3:3)) & ((gctUINT32) ((((1 ? 3:3) - (0 ? 3:3) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:3) - (0 ? 3:3) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 4:4)) & ((gctUINT32) ((((1 ? 4:4) - (0 ? 4:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 4:4) - (0 ? 4:4) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 5:5)) & ((gctUINT32) ((((1 ? 5:5) - (0 ? 5:5) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:5) - (0 ? 5:5) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 6:6)) & ((gctUINT32) ((((1 ? 6:6) - (0 ? 6:6) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 6:6) - (0 ? 6:6) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 7:7)) & ((gctUINT32) ((((1 ? 7:7) - (0 ? 7:7) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 7:7) - (0 ? 7:7) + 1)))))) ) != 1) + || ((((((gctUINT32) (idle)) >> (0 ? 2:2)) & ((gctUINT32) ((((1 ? 2:2) - (0 ? 2:2) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 2:2) - (0 ? 2:2) + 1)))))) ) != 1) + ) + { + /* Something is busy. */ + *IsIdle = gcvFALSE; + } + + else + { + /* Read the current FE address. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00664, + &address)); + + /* Test if address is inside the last WAIT/LINK sequence. */ + if ((address >= Hardware->lastWaitLink) + && (address <= Hardware->lastWaitLink + 16) + ) + { + /* FE is in last WAIT/LINK and the pipe is idle. */ + *IsIdle = gcvTRUE; + } + else + { + /* FE is not in WAIT/LINK yet. */ + *IsIdle = gcvFALSE; + } + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** Handy macros that will help in reading those debug registers. +*/ + +#define gcmkREAD_DEBUG_REGISTER(control, block, index, data) \ + gcmkONERROR(\ + gckOS_WriteRegisterEx(Hardware->os, \ + Hardware->core, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + index))); \ + gcmkONERROR(\ + gckOS_ReadRegisterEx(Hardware->os, \ + Hardware->core, \ + GC_DEBUG_SIGNALS_##block##_Address, \ + &profiler->data)) + +#define gcmkRESET_DEBUG_REGISTER(control, block) \ + gcmkONERROR(\ + gckOS_WriteRegisterEx(Hardware->os, \ + Hardware->core, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 15))); \ + gcmkONERROR(\ + gckOS_WriteRegisterEx(Hardware->os, \ + Hardware->core, \ + GC_DEBUG_CONTROL##control##_Address, \ + gcmSETFIELD(0, \ + GC_DEBUG_CONTROL##control, \ + block, \ + 0))) + +/******************************************************************************* +** +** gckHARDWARE_ProfileEngine2D +** +** Read the profile registers available in the 2D engine and sets them in the +** profile. The function will also reset the pixelsRendered counter every time. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** OPTIONAL gcs2D_PROFILE_PTR Profile +** Pointer to a gcs2D_Profile structure. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OPTIONAL gcs2D_PROFILE_PTR Profile + ) +{ + gceSTATUS status; + gcs2D_PROFILE_PTR profiler = Profile; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (Profile != gcvNULL) + { + /* Read the cycle count. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00438, + &Profile->cycleCount)); + + /* Read pixels rendered by 2D engine. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pixelsRendered)); + + /* Reset counter. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ) +{ + gceSTATUS status; + gcsPROFILER_COUNTERS * profiler = Counters; + + gcmkHEADER_ARG("Hardware=0x%x Counters=0x%x", Hardware, Counters); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Read the counters. */ + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00040, + &profiler->gpuTotalRead64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00044, + &profiler->gpuTotalWrite64BytesPerFrame)); + gcmkONERROR( + gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00438, + &profiler->gpuCyclesCounter)); + + /* Reset counters. */ + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 1)); + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x0003C, 0)); + gcmkONERROR( + gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00438, 0)); + + /* PE */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pe_pixel_count_killed_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pe_pixel_count_killed_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pe_pixel_count_drawn_by_color_pipe)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00454, &profiler->pe_pixel_count_drawn_by_depth_pipe)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +)); + + /* SH */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->ps_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_pixel_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vs_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->rendered_vertice_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (11) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (12) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->vtx_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (13) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_branch_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (14) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0045C, &profiler->pxl_texld_inst_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00470, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +)); + + /* PA */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_vtx_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (4) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_input_prim_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_output_prim_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_depth_clipped_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_trivial_rejected_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00460, &profiler->pa_culled_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +)); + + /* SE */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_triangle_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00464, &profiler->se_culled_lines_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +)); + + /* RA */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_pixel_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_quad_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_valid_quad_count_after_early_z)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_total_primitive_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_pipe_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (10) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00448, &profiler->ra_prefetch_cache_miss_counter)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:16) - (0 ? 19:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:16) - (0 ? 19:16) + 1))))))) << (0 ? 19:16))) +)); + + /* TX */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_bilinear_requests)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_trilinear_requests)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_discarded_texture_requests)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_total_texture_requests)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (5) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (6) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_mem_read_in_8B_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (7) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (8) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_hit_texel_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (9) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0044C, &profiler->tx_cache_miss_texel_count)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00474, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 27:24) - (0 ? 27:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 27:24) - (0 ? 27:24) + 1))))))) << (0 ? 27:24))) +)); + + /* MC */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_read_req_8B_from_IP)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (3) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x00468, &profiler->mc_total_write_req_8B_from_pipeline)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 3:0) - (0 ? 3:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 3:0) - (0 ? 3:0) + 1))))))) << (0 ? 3:0))) +)); + + /* HI */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_read_request_stalled)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_request_stalled)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (2) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, Hardware->core, 0x0046C, &profiler->hi_axi_cycles_write_data_stalled)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (15) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) )); +gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, 0x00478, ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 11:8) - (0 ? 11:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 11:8) - (0 ? 11:8) + 1))))))) << (0 ? 11:8))) +)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +static gceSTATUS +_ResetGPU( + IN gckHARDWARE Hardware, + IN gckOS Os, + IN gceCORE Core + ) +{ + gctUINT32 control, idle; + gceSTATUS status; + + for (;;) + { + /* Disable clock gating. */ + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + Hardware->powerBaseAddress + + 0x00104, + 0x00000000)); + + control = ((((gctUINT32) (0x01590880)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1))))))) << (0 ? 17:17))); + + /* Disable pulse-eater. */ + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x0010C, + control)); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x0010C, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1))))))) << (0 ? 0:0))))); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x0010C, + control)); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + ((((gctUINT32) (0x00000100)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 9:9) - (0 ? 9:9) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 9:9) - (0 ? 9:9) + 1))))))) << (0 ? 9:9))))); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + 0x00000100)); + + /* Wait for clock being stable. */ + gcmkONERROR(gckOS_Delay(Os, 1)); + + /* Isolate the GPU. */ + control = ((((gctUINT32) (0x00000100)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + control)); + + /* Set soft reset. */ + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Wait for reset. */ + gcmkONERROR(gckOS_Delay(Os, 1)); + + /* Reset soft reset bit. */ + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))))); + + /* Reset GPU isolation. */ + control = ((((gctUINT32) (control)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))) | (((gctUINT32) ((gctUINT32) (0) & ((gctUINT32) ((((1 ? 19:19) - (0 ? 19:19) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 19:19) - (0 ? 19:19) + 1))))))) << (0 ? 19:19))); + + gcmkONERROR(gckOS_WriteRegisterEx(Os, + Core, + 0x00000, + control)); + + /* Read idle register. */ + gcmkONERROR(gckOS_ReadRegisterEx(Os, + Core, + 0x00004, + &idle)); + + if ((((((gctUINT32) (idle)) >> (0 ? 0:0)) & ((gctUINT32) ((((1 ? 0:0) - (0 ? 0:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 0:0) - (0 ? 0:0) + 1)))))) ) == 0) + { + continue; + } + + /* Read reset register. */ + gcmkONERROR(gckOS_ReadRegisterEx(Os, + Core, + 0x00000, + &control)); + + if (((((((gctUINT32) (control)) >> (0 ? 16:16)) & ((gctUINT32) ((((1 ? 16:16) - (0 ? 16:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 16:16) - (0 ? 16:16) + 1)))))) ) == 0) + || ((((((gctUINT32) (control)) >> (0 ? 17:17)) & ((gctUINT32) ((((1 ? 17:17) - (0 ? 17:17) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 17:17) - (0 ? 17:17) + 1)))))) ) == 0) + ) + { + continue; + } + + /* GPU is idle. */ + break; + } + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + + /* Return the error. */ + return status; +} + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ) +{ + gceSTATUS status; + gckCOMMAND command; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_OBJECT(Hardware->kernel, gcvOBJ_KERNEL); + command = Hardware->kernel->command; + gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); + + if (Hardware->identity.chipRevision < 0x4600) + { + /* Not supported - we need the isolation bit. */ + gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); + } + + if (Hardware->chipPowerState == gcvPOWER_ON) + { + /* Acquire the power management semaphore. */ + gcmkONERROR( + gckOS_AcquireSemaphore(Hardware->os, command->powerSemaphore)); + acquired = gcvTRUE; + } + + if ((Hardware->chipPowerState == gcvPOWER_ON) + || (Hardware->chipPowerState == gcvPOWER_IDLE) + ) + { + /* Stop the command processor. */ + gcmkONERROR(gckCOMMAND_Stop(command, gcvTRUE)); + } + + /* Stop isr, we will start it again when power on GPU. */ + gcmkONERROR(Hardware->stopIsr(Hardware->isrContext)); + + gcmkONERROR(_ResetGPU(Hardware, Hardware->os, Hardware->core)); + + /* Force an OFF to ON power switch. */ + Hardware->chipPowerState = gcvPOWER_OFF; + gcmkONERROR(gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK( + gckOS_ReleaseSemaphore(Hardware->os, command->powerSemaphore)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Test if we have a new Memory Controller. */ + if (((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))))) + { + /* No base address required. */ + *BaseAddress = 0; + } + else + { + /* Get the base address from the OS. */ + gcmkONERROR(gckOS_GetBaseAddress(Hardware->os, BaseAddress)); + } + + /* Success. */ + gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ) +{ + gctBOOL need = gcvFALSE; + + gcmkHEADER_ARG("Hardware=0x%x State=0x%08x", Hardware, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(NeedBase != gcvNULL); + + /* Make sure this is a load state. */ + if (((((gctUINT32) (State)) >> (0 ? 31:27) & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))) == (0x01 & ((gctUINT32) ((((1 ? 31:27) - (0 ? 31:27) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 31:27) - (0 ? 31:27) + 1)))))))) + { +#ifndef VIVANTE_NO_3D + /* Get the state address. */ + switch ((((((gctUINT32) (State)) >> (0 ? 15:0)) & ((gctUINT32) ((((1 ? 15:0) - (0 ? 15:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 15:0) - (0 ? 15:0) + 1)))))) )) + { + case 0x0596: + case 0x0597: + case 0x0599: + case 0x059A: + case 0x05A9: + /* These states need a TRUE physical address. */ + need = gcvTRUE; + break; + } +#else + /* 2D addresses don't need a base address. */ +#endif + } + + /* Return the flag. */ + *NeedBase = need; + + /* Success. */ + gcmkFOOTER_ARG("*NeedBase=%d", *NeedBase); + return gcvSTATUS_OK; +} + +gceSTATUS +gckHARDWARE_SetIsrManager( + IN gckHARDWARE Hardware, + IN gctISRMANAGERFUNC StartIsr, + IN gctISRMANAGERFUNC StopIsr, + IN gctPOINTER Context + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Hardware=0x%x, StartIsr=0x%x, StopIsr=0x%x, Context=0x%x", + Hardware, StartIsr, StopIsr, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + if (StartIsr == gcvNULL || + StopIsr == gcvNULL || + Context == gcvNULL) + { + status = gcvSTATUS_INVALID_ARGUMENT; + + gcmkFOOTER(); + return status; + } + + Hardware->startIsr = StartIsr; + Hardware->stopIsr = StopIsr; + Hardware->isrContext = Context; + + /* Success. */ + gcmkFOOTER(); + + return status; +} + +/******************************************************************************* +** +** gckHARDWARE_Compose +** +** Start a composition. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHARDWARE_Compose( + IN gckHARDWARE Hardware, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Offset, + IN gctSIZE_T Size, + IN gctUINT8 EventID + ) +{ +#ifndef VIVANTE_NO_3D + gceSTATUS status; + gctUINT32_PTR triggerState; + + gcmkHEADER_ARG("Hardware=0x%x Physical=0x%x Logical=0x%x" + " Offset=%d Size=%d EventID=%d", + Hardware, Physical, Logical, Offset, Size, EventID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + gcmkVERIFY_ARGUMENT(((Size + 8) & 63) == 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Program the trigger state. */ + triggerState = (gctUINT32_PTR) ((gctUINT8_PTR) Logical + Offset + Size); + triggerState[0] = 0x0C03; + triggerState[1] + = ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x1 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 5:4) - (0 ? 5:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 5:4) - (0 ? 5:4) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 5:4) - (0 ? 5:4) + 1))))))) << (0 ? 5:4))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 8:8) - (0 ? 8:8) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 8:8) - (0 ? 8:8) + 1))))))) << (0 ? 8:8))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 24:24) - (0 ? 24:24) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 24:24) - (0 ? 24:24) + 1))))))) << (0 ? 24:24))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) | (((gctUINT32) ((gctUINT32) (1) & ((gctUINT32) ((((1 ? 12:12) - (0 ? 12:12) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 12:12) - (0 ? 12:12) + 1))))))) << (0 ? 12:12))) + | ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 20:16) - (0 ? 20:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16))) | (((gctUINT32) ((gctUINT32) (EventID) & ((gctUINT32) ((((1 ? 20:16) - (0 ? 20:16) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 20:16) - (0 ? 20:16) + 1))))))) << (0 ? 20:16))) + ; + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache for the wait/link. */ + gcmkONERROR(gckOS_CacheClean( + Hardware->os, ProcessID, gcvNULL, + Physical, Logical, Offset + Size + )); +#endif + + /* Start composition. */ + gcmkONERROR(gckOS_WriteRegisterEx( + Hardware->os, Hardware->core, 0x00554, + ((((gctUINT32) (0)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) | (((gctUINT32) (0x3 & ((gctUINT32) ((((1 ? 1:0) - (0 ? 1:0) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 1:0) - (0 ? 1:0) + 1))))))) << (0 ? 1:0))) + )); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + /* Return the status. */ + return gcvSTATUS_NOT_SUPPORTED; +#endif +} + +/******************************************************************************* +** +** gckHARDWARE_IsFeatureAvailable +** +** Verifies whether the specified feature is available in hardware. +** +** INPUT: +** +** gckHARDWARE Hardware +** Pointer to an gckHARDWARE object. +** +** gceFEATURE Feature +** Feature to be verified. +*/ +gceSTATUS +gckHARDWARE_IsFeatureAvailable( + IN gckHARDWARE Hardware, + IN gceFEATURE Feature + ) +{ + gctBOOL available; + + gcmkHEADER_ARG("Hardware=0x%x Feature=%d", Hardware, Feature); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + /* Only features needed by common kernel logic added here. */ + switch (Feature) + { + case gcvFEATURE_END_EVENT: + /*available = gcmVERIFYFIELDVALUE(Hardware->identity.chipMinorFeatures2, + GC_MINOR_FEATURES2, END_EVENT, AVAILABLE + );*/ + available = gcvFALSE; + break; + case gcvFEATURE_MC20: + available = ((((gctUINT32) (Hardware->identity.chipMinorFeatures)) >> (0 ? 22:22) & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1)))))) == (0x1 & ((gctUINT32) ((((1 ? 22:22) - (0 ? 22:22) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 22:22) - (0 ? 22:22) + 1))))))); + break; + + default: + gcmkFATAL("Invalid feature has been requested."); + available = gcvFALSE; + } + + /* Return result. */ + gcmkFOOTER_ARG("%d", available ? gcvSTATUS_TRUE : gcvSTATUS_OK); + return available ? gcvSTATUS_TRUE : gcvSTATUS_OK; +} + +#if gcdFRAME_DB +static gceSTATUS +gckHARDWARE_ReadPerformanceRegister( + IN gckHARDWARE Hardware, + IN gctUINT PerformanceAddress, + IN gctUINT IndexAddress, + IN gctUINT IndexShift, + IN gctUINT Index, + OUT gctUINT32_PTR Value + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Hardware=0x%x PerformanceAddress=0x%x IndexAddress=0x%x " + "IndexShift=%u Index=%u", + Hardware, PerformanceAddress, IndexAddress, IndexShift, + Index); + + /* Write the index. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + IndexAddress, + Index << IndexShift)); + + /* Read the register. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + PerformanceAddress, + Value)); + + /* Test for reset. */ + if (Index == 15) + { + /* Index another register to get out of reset. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, Hardware->core, IndexAddress, 0)); + } + + /* Success. */ + gcmkFOOTER_ARG("*Value=0x%x", *Value); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckHARDWARE_GetFrameInfo( + IN gckHARDWARE Hardware, + OUT gcsHAL_FRAME_INFO * FrameInfo + ) +{ + gceSTATUS status; + gctUINT i, clock; + gcsHAL_FRAME_INFO info; +#if gcdFRAME_DB_RESET + gctUINT reset; +#endif + + gcmkHEADER_ARG("Hardware=0x%x", Hardware); + + /* Get profile tick. */ + gcmkONERROR(gckOS_GetProfileTick(&info.ticks)); + + /* Read SH counters and reset them. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 4, + &info.shaderCycles)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 9, + &info.vsInstructionCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 12, + &info.vsTextureCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 7, + &info.psInstructionCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 14, + &info.psTextureCount)); +#if gcdFRAME_DB_RESET + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0045C, + 0x00470, + 24, + 15, + &reset)); +#endif + + /* Read PA counters and reset them. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 3, + &info.vertexCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 4, + &info.primitiveCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 7, + &info.rejectedPrimitives)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 8, + &info.culledPrimitives)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 6, + &info.clippedPrimitives)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 5, + &info.outPrimitives)); +#if gcdFRAME_DB_RESET + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00460, + 0x00474, + 0, + 15, + &reset)); +#endif + + /* Read RA counters and reset them. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 3, + &info.inPrimitives)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 11, + &info.culledQuadCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 1, + &info.totalQuadCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 2, + &info.quadCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 0, + &info.totalPixelCount)); +#if gcdFRAME_DB_RESET + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00448, + 0x00474, + 16, + 15, + &reset)); +#endif + + /* Read TX counters and reset them. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 0, + &info.bilinearRequests)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 1, + &info.trilinearRequests)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 8, + &info.txHitCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 9, + &info.txMissCount)); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 6, + &info.txBytes8)); +#if gcdFRAME_DB_RESET + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x0044C, + 0x00474, + 24, + 15, + &reset)); +#endif + + /* Read clock control register. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00000, + &clock)); + + /* Walk through all avaiable pixel pipes. */ + for (i = 0; i < Hardware->identity.pixelPipes; ++i) + { + /* Select proper pipe. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00000, + ((((gctUINT32) (clock)) & ~(((gctUINT32) (((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))) | (((gctUINT32) ((gctUINT32) (i) & ((gctUINT32) ((((1 ? 23:20) - (0 ? 23:20) + 1) == 32) ? ~0 : (~(~0 << ((1 ? 23:20) - (0 ? 23:20) + 1))))))) << (0 ? 23:20))))); + + /* Read cycle registers. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00078, + &info.cycles[i])); + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x0007C, + &info.idleCycles[i])); + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00438, + &info.mcCycles[i])); + + /* Read bandwidth registers. */ + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x0005C, + &info.readRequests[i])); + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00040, + &info.readBytes8[i])); + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00050, + &info.writeRequests[i])); + gcmkONERROR(gckOS_ReadRegisterEx(Hardware->os, + Hardware->core, + 0x00044, + &info.writeBytes8[i])); + + /* Read PE counters. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00454, + 0x00470, + 16, + 0, + &info.colorKilled[i])); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00454, + 0x00470, + 16, + 2, + &info.colorDrawn[i])); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00454, + 0x00470, + 16, + 1, + &info.depthKilled[i])); + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00454, + 0x00470, + 16, + 3, + &info.depthDrawn[i])); + } + + /* Zero out remaning reserved counters. */ + for (; i < 8; ++i) + { + info.readBytes8[i] = 0; + info.writeBytes8[i] = 0; + info.cycles[i] = 0; + info.idleCycles[i] = 0; + info.mcCycles[i] = 0; + info.readRequests[i] = 0; + info.writeRequests[i] = 0; + info.colorKilled[i] = 0; + info.colorDrawn[i] = 0; + info.depthKilled[i] = 0; + info.depthDrawn[i] = 0; + } + + /* Reset clock control register. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00000, + clock)); + + /* Reset cycle and bandwidth counters. */ + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0003C, + 1)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x0003C, + 0)); + gcmkONERROR(gckOS_WriteRegisterEx(Hardware->os, + Hardware->core, + 0x00078, + 0)); + +#if gcdFRAME_DB_RESET + /* Reset PE counters. */ + gcmkONERROR(gckHARDWARE_ReadPerformanceRegister( + Hardware, + 0x00454, + 0x00470, + 16, + 15, + &reset)); +#endif + + /* Copy to user. */ + gcmkONERROR(gckOS_CopyToUserData(Hardware->os, + &info, + FrameInfo, + gcmSIZEOF(info))); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + diff --git a/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h new file mode 100644 index 0000000..caf84c7 --- /dev/null +++ b/kernel_drivers/v4/arch/XAQ2/hal/kernel/gc_hal_kernel_hardware.h @@ -0,0 +1,112 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_hardware_h_ +#define __gc_hal_kernel_hardware_h_ + +#if gcdENABLE_VG +#include "gc_hal_kernel_hardware_vg.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* gckHARDWARE object. */ +struct _gckHARDWARE +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gctKERNEL object. */ + gckKERNEL kernel; + + /* Pointer to gctOS object. */ + gckOS os; + + /* Core */ + gceCORE core; + + /* Chip characteristics. */ + gcsHAL_QUERY_CHIP_IDENTITY identity; + gctBOOL allowFastClear; + gctBOOL allowCompression; + gctUINT32 powerBaseAddress; + gctBOOL extraEventStates; + + /* Big endian */ + gctBOOL bigEndian; + + /* Chip status */ + gctPOINTER powerMutex; + gctUINT32 powerProcess; + gctUINT32 powerThread; + gceCHIPPOWERSTATE chipPowerState; + gctUINT32 lastWaitLink; + gctBOOL clockState; + gctBOOL powerState; + gctPOINTER globalSemaphore; + + gctISRMANAGERFUNC startIsr; + gctISRMANAGERFUNC stopIsr; + gctPOINTER isrContext; + + gctUINT32 mmuVersion; + + /* Type */ + gceHARDWARE_TYPE type; + +#if gcdPOWEROFF_TIMEOUT + gctUINT32 powerOffTime; + gctUINT32 powerOffTimeout; + gctPOINTER powerOffTimer; +#endif + + gctPOINTER pageTableDirty; +}; + +gceSTATUS +gckHARDWARE_GetBaseAddress( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR BaseAddress + ); + +gceSTATUS +gckHARDWARE_NeedBaseAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 State, + OUT gctBOOL_PTR NeedBase + ); + +gceSTATUS +gckHARDWARE_GetFrameInfo( + IN gckHARDWARE Hardware, + OUT gcsHAL_FRAME_INFO * FrameInfo + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_hardware_h_ */ + diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel.c new file mode 100644 index 0000000..4fe7bb8 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel.c @@ -0,0 +1,2734 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************* +***** Version Signature *******************************************************/ + +#define _gcmTXT2STR(t) #t +#define gcmTXT2STR(t) _gcmTXT2STR(t) +const char * _VERSION = "\n\0$VERSION$" + gcmTXT2STR(gcvVERSION_MAJOR) "." + gcmTXT2STR(gcvVERSION_MINOR) "." + gcmTXT2STR(gcvVERSION_PATCH) ":" + gcmTXT2STR(gcvVERSION_BUILD) "$\n"; + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) +#define gcmDEFINE2TEXT(d) #d +gctCONST_STRING _DispatchText[] = +{ + gcmDEFINE2TEXT(gcvHAL_QUERY_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_QUERY_CHIP_IDENTITY), + gcmDEFINE2TEXT(gcvHAL_ALLOCATE_NON_PAGED_MEMORY), + gcmDEFINE2TEXT(gcvHAL_FREE_NON_PAGED_MEMORY), + gcmDEFINE2TEXT(gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY), + gcmDEFINE2TEXT(gcvHAL_FREE_CONTIGUOUS_MEMORY), + gcmDEFINE2TEXT(gcvHAL_ALLOCATE_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_FREE_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_MAP_MEMORY), + gcmDEFINE2TEXT(gcvHAL_UNMAP_MEMORY), + gcmDEFINE2TEXT(gcvHAL_MAP_USER_MEMORY), + gcmDEFINE2TEXT(gcvHAL_UNMAP_USER_MEMORY), + gcmDEFINE2TEXT(gcvHAL_LOCK_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_UNLOCK_VIDEO_MEMORY), + gcmDEFINE2TEXT(gcvHAL_EVENT_COMMIT), + gcmDEFINE2TEXT(gcvHAL_USER_SIGNAL), + gcmDEFINE2TEXT(gcvHAL_SIGNAL), + gcmDEFINE2TEXT(gcvHAL_WRITE_DATA), + gcmDEFINE2TEXT(gcvHAL_COMMIT), + gcmDEFINE2TEXT(gcvHAL_STALL), + gcmDEFINE2TEXT(gcvHAL_READ_REGISTER), + gcmDEFINE2TEXT(gcvHAL_WRITE_REGISTER), + gcmDEFINE2TEXT(gcvHAL_GET_PROFILE_SETTING), + gcmDEFINE2TEXT(gcvHAL_SET_PROFILE_SETTING), + gcmDEFINE2TEXT(gcvHAL_READ_ALL_PROFILE_REGISTERS), + gcmDEFINE2TEXT(gcvHAL_PROFILE_REGISTERS_2D), + gcmDEFINE2TEXT(gcvHAL_SET_POWER_MANAGEMENT_STATE), + gcmDEFINE2TEXT(gcvHAL_QUERY_POWER_MANAGEMENT_STATE), + gcmDEFINE2TEXT(gcvHAL_GET_BASE_ADDRESS), + gcmDEFINE2TEXT(gcvHAL_SET_IDLE), + gcmDEFINE2TEXT(gcvHAL_QUERY_KERNEL_SETTINGS), + gcmDEFINE2TEXT(gcvHAL_RESET), + gcmDEFINE2TEXT(gcvHAL_MAP_PHYSICAL), + gcmDEFINE2TEXT(gcvHAL_DEBUG), + gcmDEFINE2TEXT(gcvHAL_CACHE), + gcmDEFINE2TEXT(gcvHAL_TIMESTAMP), + gcmDEFINE2TEXT(gcvHAL_DATABASE), + gcmDEFINE2TEXT(gcvHAL_VERSION), + gcmDEFINE2TEXT(gcvHAL_CHIP_INFO), + gcmDEFINE2TEXT(gcvHAL_ATTACH), + gcmDEFINE2TEXT(gcvHAL_DETACH) +}; +#endif + +/******************************************************************************* +** +** gckKERNEL_Construct +** +** Construct a new gckKERNEL object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gceCORE Core +** Specified core. +** +** IN gctPOINTER Context +** Pointer to a driver defined context. +** +** IN gckDB SharedDB, +** Pointer to a shared DB. +** +** OUTPUT: +** +** gckKERNEL * Kernel +** Pointer to a variable that will hold the pointer to the gckKERNEL +** object. +*/ +#ifdef ANDROID +#if gcdNEW_PROFILER_FILE +#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.vpd" +#else +#define DEFAULT_PROFILE_FILE_NAME "/sdcard/vprofiler.xml" +#endif +#else +#if gcdNEW_PROFILER_FILE +#define DEFAULT_PROFILE_FILE_NAME "vprofiler.vpd" +#else +#define DEFAULT_PROFILE_FILE_NAME "vprofiler.xml" +#endif +#endif + +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Context, + IN gckDB SharedDB, + OUT gckKERNEL * Kernel + ) +{ + gckKERNEL kernel = gcvNULL; + gceSTATUS status; + gctSIZE_T i; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); + + /* Allocate the gckKERNEL object. */ + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(struct _gckKERNEL), + &pointer)); + + kernel = pointer; + + /* Zero the object pointers. */ + kernel->hardware = gcvNULL; + kernel->command = gcvNULL; + kernel->eventObj = gcvNULL; + kernel->mmu = gcvNULL; + + if (SharedDB == gcvNULL) + { + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(struct _gckDB), + &pointer)); + + kernel->db = pointer; + kernel->dbCreated = gcvTRUE; + kernel->db->freeDatabase = gcvNULL; + kernel->db->freeRecord = gcvNULL; + kernel->db->dbMutex = gcvNULL; + kernel->db->lastDatabase = gcvNULL; + kernel->db->idleTime = 0; + kernel->db->lastIdle = 0; + kernel->db->lastSlowdown = 0; + + for (i = 0; i < gcmCOUNTOF(kernel->db->db); ++i) + { + kernel->db->db[i] = gcvNULL; + } + + /* Construct a database mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &kernel->db->dbMutex)); + } + else + { + kernel->db = SharedDB; + kernel->dbCreated = gcvFALSE; + } + + for (i = 0; i < gcmCOUNTOF(kernel->timers); ++i) + { + kernel->timers[i].startTime = 0; + kernel->timers[i].stopTime = 0; + } + + kernel->timeOut = gcdGPU_TIMEOUT; + + /* Initialize the gckKERNEL object. */ + kernel->object.type = gcvOBJ_KERNEL; + kernel->os = Os; + kernel->core = Core; + + /* Save context. */ + kernel->context = Context; + + /* Construct atom holding number of clients. */ + kernel->atomClients = gcvNULL; + gcmkONERROR(gckOS_AtomConstruct(Os, &kernel->atomClients)); + +#if gcdENABLE_VG + kernel->vg = gcvNULL; + + if (Core == gcvCORE_VG) + { + /* Construct the gckMMU object. */ + gcmkONERROR( + gckVGKERNEL_Construct(Os, Context, kernel, &kernel->vg)); + } + else +#endif + { + /* Construct the gckHARDWARE object. */ + gcmkONERROR( + gckHARDWARE_Construct(Os, kernel->core, &kernel->hardware)); + + /* Set pointer to gckKERNEL object in gckHARDWARE object. */ + kernel->hardware->kernel = kernel; + + /* Initialize the hardware. */ + gcmkONERROR( + gckHARDWARE_InitializeHardware(kernel->hardware)); + + /* Construct the gckCOMMAND object. */ + gcmkONERROR( + gckCOMMAND_Construct(kernel, &kernel->command)); + + /* Construct the gckEVENT object. */ + gcmkONERROR( + gckEVENT_Construct(kernel, &kernel->eventObj)); + + /* Construct the gckMMU object. */ + gcmkONERROR( + gckMMU_Construct(kernel, gcdMMU_SIZE, &kernel->mmu)); + } + +#if VIVANTE_PROFILER + /* Initialize profile setting */ +#if defined ANDROID + kernel->profileEnable = gcvFALSE; +#else + kernel->profileEnable = gcvTRUE; +#endif + + gcmkVERIFY_OK( + gckOS_MemCopy(kernel->profileFileName, + DEFAULT_PROFILE_FILE_NAME, + gcmSIZEOF(DEFAULT_PROFILE_FILE_NAME) + 1)); +#endif + + /* Return pointer to the gckKERNEL object. */ + *Kernel = kernel; + + /* Success. */ + gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); + return gcvSTATUS_OK; + +OnError: + if (kernel != gcvNULL) + { +#if gcdENABLE_VG + if (Core != gcvCORE_VG) +#endif + { + if (kernel->eventObj != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_Destroy(kernel->eventObj)); + } + + if (kernel->command != gcvNULL) + { + gcmkVERIFY_OK(gckCOMMAND_Destroy(kernel->command)); + } + + if (kernel->hardware != gcvNULL) + { + gcmkVERIFY_OK(gckHARDWARE_Destroy(kernel->hardware)); + } + } + + if (kernel->atomClients != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(Os, kernel->atomClients)); + } + + if (kernel->dbCreated && kernel->db != gcvNULL) + { + if (kernel->db->dbMutex != gcvNULL) + { + /* Destroy the database mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, kernel->db->dbMutex)); + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel->db)); + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, kernel)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Destroy +** +** Destroy an gckKERNEL object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ) +{ + gctSIZE_T i; + gcsDATABASE_PTR database, databaseNext; + gcsDATABASE_RECORD_PTR record, recordNext; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); +#if QNX_SINGLE_THREADED_DEBUGGING + gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->debugMutex)); +#endif + + /* Destroy the database. */ + if (Kernel->dbCreated) + { + for (i = 0; i < gcmCOUNTOF(Kernel->db->db); ++i) + { + if (Kernel->db->db[i] != gcvNULL) + { + gcmkVERIFY_OK( + gckKERNEL_DestroyProcessDB(Kernel, Kernel->db->db[i]->processID)); + } + } + + /* Free all databases. */ + for (database = Kernel->db->freeDatabase; + database != gcvNULL; + database = databaseNext) + { + databaseNext = database->next; + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, database)); + } + + if (Kernel->db->lastDatabase != gcvNULL) + { + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel->db->lastDatabase)); + } + + /* Free all database records. */ + for (record = Kernel->db->freeRecord; record != gcvNULL; record = recordNext) + { + recordNext = record->next; + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record)); + } + + /* Destroy the database mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Kernel->os, Kernel->db->dbMutex)); + } + +#if gcdENABLE_VG + if (Kernel->vg) + { + gcmkVERIFY_OK(gckVGKERNEL_Destroy(Kernel->vg)); + } + else +#endif + { + /* Destroy the gckMMU object. */ + gcmkVERIFY_OK(gckMMU_Destroy(Kernel->mmu)); + + /* Destroy the gckCOMMNAND object. */ + gcmkVERIFY_OK(gckCOMMAND_Destroy(Kernel->command)); + + /* Destroy the gckEVENT object. */ + gcmkVERIFY_OK(gckEVENT_Destroy(Kernel->eventObj)); + + /* Destroy the gckHARDWARE object. */ + gcmkVERIFY_OK(gckHARDWARE_Destroy(Kernel->hardware)); + } + + /* Detsroy the client atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Kernel->os, Kernel->atomClients)); + + /* Mark the gckKERNEL object as unknown. */ + Kernel->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckKERNEL object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, Kernel)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** _AllocateMemory +** +** Private function to walk all required memory pools to allocate the requested +** amount of video memory. +** +** 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. +*/ +static gceSTATUS +_AllocateMemory( + IN gckKERNEL Kernel, + IN OUT gcePOOL * Pool, + IN gctSIZE_T Bytes, + IN gctSIZE_T Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gcePOOL pool; + gceSTATUS status; + gckVIDMEM videoMemory; + gctINT loopCount; + gcuVIDMEM_NODE_PTR node = gcvNULL; + gctBOOL tileStatusInVirtual; + + gcmkHEADER_ARG("Kernel=0x%x *Pool=%d Bytes=%lu Alignment=%lu Type=%d", + Kernel, *Pool, Bytes, Alignment, Type); + + gcmkVERIFY_ARGUMENT(Pool != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes != 0); + + /* Get initial pool. */ + switch (pool = *Pool) + { + case gcvPOOL_DEFAULT: + case gcvPOOL_LOCAL: + pool = gcvPOOL_LOCAL_INTERNAL; + loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; + break; + + case gcvPOOL_UNIFIED: + pool = gcvPOOL_SYSTEM; + loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; + break; + + case gcvPOOL_CONTIGUOUS: + loopCount = (gctINT) gcvPOOL_NUMBER_OF_POOLS; + break; + + default: + loopCount = 1; + break; + } + + while (loopCount-- > 0) + { + if (pool == gcvPOOL_VIRTUAL) + { + /* Create a gcuVIDMEM_NODE for virtual memory. */ + gcmkONERROR( + gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, &node)); + + /* Success. */ + break; + } + + else + if (pool == gcvPOOL_CONTIGUOUS) + { + /* Create a gcuVIDMEM_NODE for contiguous memory. */ + status = gckVIDMEM_ConstructVirtual(Kernel, gcvTRUE, Bytes, &node); + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + break; + } + } + + else + { + /* Get pointer to gckVIDMEM object for pool. */ +#if gcdUSE_VIDMEM_PER_PID + gctUINT32 pid; + gckOS_GetProcessID(&pid); + + status = gckKERNEL_GetVideoMemoryPoolPid(Kernel, pool, pid, &videoMemory); + if (status == gcvSTATUS_NOT_FOUND) + { + /* Create VidMem pool for this process. */ + status = gckKERNEL_CreateVideoMemoryPoolPid(Kernel, pool, pid, &videoMemory); + } +#else + status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); +#endif + + if (gcmIS_SUCCESS(status)) + { + /* Allocate memory. */ + status = gckVIDMEM_AllocateLinear(videoMemory, + Bytes, + Alignment, + Type, + &node); + + if (gcmIS_SUCCESS(status)) + { + /* Memory allocated. */ + node->VidMem.pool = pool; + break; + } + } + } + + if (pool == gcvPOOL_LOCAL_INTERNAL) + { + /* Advance to external memory. */ + pool = gcvPOOL_LOCAL_EXTERNAL; + } + + else + if (pool == gcvPOOL_LOCAL_EXTERNAL) + { + /* Advance to contiguous system memory. */ + pool = gcvPOOL_SYSTEM; + } + + else + if (pool == gcvPOOL_SYSTEM) + { + /* Advance to contiguous memory. */ + pool = gcvPOOL_CONTIGUOUS; + } + + else + if (pool == gcvPOOL_CONTIGUOUS) + { + tileStatusInVirtual = + gckHARDWARE_IsFeatureAvailable(Kernel->hardware, + gcvFEATURE_MC20); + + if (Type == gcvSURF_TILE_STATUS && tileStatusInVirtual != gcvTRUE) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Advance to virtual memory. */ + pool = gcvPOOL_VIRTUAL; + } + + else + { + /* Out of pools. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + } + + if (node == gcvNULL) + { + /* Nothing allocated. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + + /* Return node and pool used for allocation. */ + *Node = node; + *Pool = pool; + + /* Return status. */ + gcmkFOOTER_ARG("*Pool=%d *Node=0x%x", *Pool, *Node); + return gcvSTATUS_OK; + +OnError: + /* Return the 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 = gcvSTATUS_OK; + gctSIZE_T bytes; + gcuVIDMEM_NODE_PTR node; + gctBOOL locked = gcvFALSE; + gctPHYS_ADDR physical = gcvNULL; + gctUINT32 address; + gctUINT32 processID; +#if gcdSECURE_USER + gcskSECURE_CACHE_PTR cache; + gctPOINTER logical; +#endif + gctBOOL asynchronous; + gctPOINTER paddr = gcvNULL; +#if !USE_NEW_LINUX_SIGNAL + gctSIGNAL signal; +#endif + + gcsDATABASE_RECORD record; + gctPOINTER data; + + 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); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, + "Dispatching command %d (%s)", + Interface->command, _DispatchText[Interface->command]); +#endif +#if QNX_SINGLE_THREADED_DEBUGGING + gckOS_AcquireMutex(Kernel->os, Kernel->debugMutex, gcvINFINITE); +#endif + + /* Get the current process ID. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + +#if gcdSECURE_USER + gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache)); +#endif + + /* 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)); + 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)); + gcmkVERIFY_OK( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_MAP_MEMORY, + Interface->u.MapMemory.logical, + physical, + Interface->u.MapMemory.bytes)); + 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)); + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_MAP_MEMORY, + Interface->u.UnmapMemory.logical)); + break; + + case gcvHAL_ALLOCATE_NON_PAGED_MEMORY: + /* Allocate non-paged memory. */ + gcmkONERROR( + gckOS_AllocateNonPagedMemory( + Kernel->os, + FromUser, + &Interface->u.AllocateNonPagedMemory.bytes, + &Interface->u.AllocateNonPagedMemory.physical, + &Interface->u.AllocateNonPagedMemory.logical)); + + gcmkVERIFY_OK( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_NON_PAGED, + Interface->u.AllocateNonPagedMemory.logical, + Interface->u.AllocateNonPagedMemory.physical, + Interface->u.AllocateNonPagedMemory.bytes)); + 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)); + + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_NON_PAGED, + Interface->u.FreeNonPagedMemory.logical)); + +#if gcdSECURE_USER + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Kernel, + cache, + Interface->u.FreeNonPagedMemory.logical, + Interface->u.FreeNonPagedMemory.bytes)); +#endif + break; + + case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: + /* Allocate contiguous memory. */ + gcmkONERROR(gckOS_AllocateContiguous( + Kernel->os, + FromUser, + &Interface->u.AllocateContiguousMemory.bytes, + &Interface->u.AllocateContiguousMemory.physical, + &Interface->u.AllocateContiguousMemory.logical)); + + gcmkONERROR(gckHARDWARE_ConvertLogical( + Kernel->hardware, + Interface->u.AllocateContiguousMemory.logical, + &Interface->u.AllocateContiguousMemory.address)); + + gcmkVERIFY_OK(gckKERNEL_AddProcessDB( + Kernel, + processID, gcvDB_CONTIGUOUS, + Interface->u.AllocateContiguousMemory.logical, + Interface->u.AllocateContiguousMemory.physical, + Interface->u.AllocateContiguousMemory.bytes)); + 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)); + + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_CONTIGUOUS, + Interface->u.FreeNonPagedMemory.logical)); + +#if gcdSECURE_USER + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Kernel, + cache, + Interface->u.FreeContiguousMemory.logical, + Interface->u.FreeContiguousMemory.bytes)); +#endif + break; + + case gcvHAL_ALLOCATE_VIDEO_MEMORY: + + gcmkONERROR(gcvSTATUS_NOT_SUPPORTED); + + break; + + case gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY: + /* Allocate memory. */ + gcmkONERROR( + _AllocateMemory(Kernel, + &Interface->u.AllocateLinearVideoMemory.pool, + Interface->u.AllocateLinearVideoMemory.bytes, + Interface->u.AllocateLinearVideoMemory.alignment, + Interface->u.AllocateLinearVideoMemory.type, + &Interface->u.AllocateLinearVideoMemory.node)); + + /* Get actual size of node. */ + node = Interface->u.AllocateLinearVideoMemory.node; + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + bytes = node->VidMem.bytes; + } + else + { + bytes = node->Virtual.bytes; + } + + gcmkONERROR( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_VIDEO_MEMORY, + Interface->u.AllocateLinearVideoMemory.node, + gcvNULL, + bytes)); + 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, + processID, + node->VidMem.bytes)); + node->VidMem.logical = gcvNULL; + } +#endif + /* Free video memory. */ + gcmkONERROR( + gckVIDMEM_Free(Interface->u.FreeVideoMemory.node)); + + gcmkONERROR( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_VIDEO_MEMORY, + Interface->u.FreeVideoMemory.node)); + break; + + case gcvHAL_LOCK_VIDEO_MEMORY: + /* Lock video memory. */ + gcmkONERROR( + gckVIDMEM_Lock(Kernel, + Interface->u.LockVideoMemory.node, + Interface->u.LockVideoMemory.cacheable, + &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, + processID, + node->VidMem.bytes, + &node->VidMem.logical)); + } + gcmkASSERT(node->VidMem.logical != gcvNULL); + + Interface->u.LockVideoMemory.memory = node->VidMem.logical; +#else + gcmkONERROR( + gckKERNEL_MapVideoMemory(Kernel, + FromUser, + Interface->u.LockVideoMemory.address, + &Interface->u.LockVideoMemory.memory)); +#endif + } + else + { + 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 + gcmkONERROR( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_VIDEO_MEMORY_LOCKED, + Interface->u.LockVideoMemory.node, + gcvNULL, + 0)); + + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + /* Unlock video memory. */ + node = 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. */ + gcmkONERROR( + 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 */ + gcmkONERROR( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_VIDEO_MEMORY_LOCKED, + Interface->u.UnlockVideoMemory.node)); + } + + break; + + case gcvHAL_EVENT_COMMIT: + /* Commit an event queue. */ + gcmkONERROR( + gckEVENT_Commit(Kernel->eventObj, + Interface->u.Event.queue)); + break; + + case gcvHAL_COMMIT: + /* Commit a command and context buffer. */ + gcmkONERROR( + gckCOMMAND_Commit(Kernel->command, + Interface->u.Commit.context, + Interface->u.Commit.commandBuffer, + Interface->u.Commit.delta, + Interface->u.Commit.queue, + processID)); + break; + + case gcvHAL_STALL: + /* Stall the command queue. */ + gcmkONERROR(gckCOMMAND_Stall(Kernel->command, gcvFALSE)); + break; + + case gcvHAL_MAP_USER_MEMORY: + /* Map user memory to DMA. */ + gcmkONERROR( + gckOS_MapUserMemoryEx(Kernel->os, + Kernel->core, + Interface->u.MapUserMemory.memory, + Interface->u.MapUserMemory.size, + &Interface->u.MapUserMemory.info, + &Interface->u.MapUserMemory.address)); + gcmkVERIFY_OK( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_MAP_USER_MEMORY, + Interface->u.MapUserMemory.memory, + Interface->u.MapUserMemory.info, + Interface->u.MapUserMemory.size)); + break; + + case gcvHAL_UNMAP_USER_MEMORY: + address = Interface->u.MapUserMemory.address; + + /* Unmap user memory. */ + gcmkONERROR( + gckOS_UnmapUserMemoryEx(Kernel->os, + Kernel->core, + Interface->u.UnmapUserMemory.memory, + Interface->u.UnmapUserMemory.size, + Interface->u.UnmapUserMemory.info, + address)); + +#if gcdSECURE_USER + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Kernel, + cache, + Interface->u.UnmapUserMemory.memory, + Interface->u.UnmapUserMemory.size)); +#endif + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_MAP_USER_MEMORY, + Interface->u.UnmapUserMemory.memory)); + break; + +#if !USE_NEW_LINUX_SIGNAL + case gcvHAL_USER_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. */ + gcmkONERROR( + 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. */ + gcmkONERROR( + 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. */ + 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; + + case gcvUSER_SIGNAL_MAP: + gcmkONERROR( + gckOS_MapSignal(Kernel->os, + (gctSIGNAL)Interface->u.UserSignal.id, + (gctHANDLE)processID, + &signal)); + + gcmkVERIFY_OK( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_SIGNAL, + gcmINT2PTR(Interface->u.UserSignal.id), + gcvNULL, + 0)); + break; + + case gcvUSER_SIGNAL_UNMAP: + /* Destroy the signal. */ + gcmkONERROR( + gckOS_DestroyUserSignal(Kernel->os, + Interface->u.UserSignal.id)); + + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Kernel, + processID, gcvDB_SIGNAL, + gcmINT2PTR(Interface->u.UserSignal.id))); + 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 + { + gceCHIPPOWERSTATE power; + gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware, + &power)); + + if (power == gcvPOWER_ON) + { + /* Read a register. */ + gcmkONERROR(gckOS_ReadRegisterEx( + Kernel->os, + Kernel->core, + Interface->u.ReadRegisterData.address, + &Interface->u.ReadRegisterData.data)); + } + else + { + /* Chip is in power-state. */ + Interface->u.ReadRegisterData.data = 0; + status = gcvSTATUS_CHIP_NOT_READY; + } + } +#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_WriteRegisterEx(Kernel->os, + Kernel->core, + 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. */ + gckKERNEL_Recovery(Kernel); + 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. */ + if (Interface->u.Debug.type == gcvMESSAGE_TEXT) + { + gckOS_CopyPrint(Interface->u.Debug.message); + } + else + { + gckOS_DumpBuffer(Kernel->os, + Interface->u.Debug.message, + Interface->u.Debug.messageSize, + gceDUMP_BUFFER_FROM_USER, + gcvTRUE); + } + } + status = gcvSTATUS_OK; + break; + + case gcvHAL_DUMP_GPU_STATE: + /* Dump GPU state */ + { + gceCHIPPOWERSTATE power; + gcmkONERROR(gckHARDWARE_QueryPowerManagementState(Kernel->hardware, + &power)); + if (power == gcvPOWER_ON) + { + Interface->u.ReadRegisterData.data = 1; + gcmkVERIFY_OK( + gckOS_DumpGPUState(Kernel->os, Kernel->core)); + } + else + { + Interface->u.ReadRegisterData.data = 0; + status = gcvSTATUS_CHIP_NOT_READY; + } + } + break; + + case gcvHAL_DUMP_EVENT: + /* Dump GPU event */ + gcmkVERIFY_OK( + gckEVENT_Dump(Kernel->eventObj)); + break; + + case gcvHAL_CACHE: + if (Interface->u.Cache.node == gcvNULL) + { + /* FIXME Surface wrap some memory which is not allocated by us, + ** So we don't have physical address to handle outer cache, ignore it*/ + status = gcvSTATUS_OK; + break; + } + else if (Interface->u.Cache.node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + /* Video memory has no physical handles. */ + physical = gcvNULL; + } + else + { + /* Grab physical handle. */ + physical = Interface->u.Cache.node->Virtual.physical; + } + + switch(Interface->u.Cache.operation) + { + case gcvCACHE_FLUSH: + /* Clean and invalidate the cache. */ + status = gckOS_CacheFlush(Kernel->os, + processID, + physical, + paddr, + Interface->u.Cache.logical, + Interface->u.Cache.bytes); + break; + case gcvCACHE_CLEAN: + /* Clean the cache. */ + status = gckOS_CacheClean(Kernel->os, + processID, + physical, + paddr, + Interface->u.Cache.logical, + Interface->u.Cache.bytes); + break; + case gcvCACHE_INVALIDATE: + /* Invalidate the cache. */ + status = gckOS_CacheInvalidate(Kernel->os, + processID, + physical, + paddr, + Interface->u.Cache.logical, + Interface->u.Cache.bytes); + break; + + case gcvCACHE_MEMORY_BARRIER: + status = gckOS_MemoryBarrier(Kernel->os, + Interface->u.Cache.logical); + break; + default: + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + break; + + case gcvHAL_TIMESTAMP: + /* Check for invalid timer. */ + if ((Interface->u.TimeStamp.timer >= gcmCOUNTOF(Kernel->timers)) + || (Interface->u.TimeStamp.request != 2)) + { + Interface->u.TimeStamp.timeDelta = 0; + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Return timer results and reset timer. */ + { + gcsTIMER_PTR timer = &(Kernel->timers[Interface->u.TimeStamp.timer]); + gctUINT64 timeDelta = 0; + + if (timer->stopTime < timer->startTime ) + { + Interface->u.TimeStamp.timeDelta = 0; + gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW); + } + + timeDelta = timer->stopTime - timer->startTime; + + /* Check truncation overflow. */ + Interface->u.TimeStamp.timeDelta = (gctINT32) timeDelta; + /*bit0~bit30 is available*/ + if (timeDelta>>31) + { + Interface->u.TimeStamp.timeDelta = 0; + gcmkONERROR(gcvSTATUS_TIMER_OVERFLOW); + } + + status = gcvSTATUS_OK; + } + break; + + case gcvHAL_DATABASE: + /* Query video memory. */ + gcmkONERROR( + gckKERNEL_QueryProcessDB(Kernel, + Interface->u.Database.processID, + !Interface->u.Database.validProcessID, + gcvDB_VIDEO_MEMORY, + &Interface->u.Database.vidMem)); + + /* Query non-paged memory. */ + gcmkONERROR( + gckKERNEL_QueryProcessDB(Kernel, + Interface->u.Database.processID, + !Interface->u.Database.validProcessID, + gcvDB_NON_PAGED, + &Interface->u.Database.nonPaged)); + + /* Query contiguous memory. */ + gcmkONERROR( + gckKERNEL_QueryProcessDB(Kernel, + Interface->u.Database.processID, + !Interface->u.Database.validProcessID, + gcvDB_CONTIGUOUS, + &Interface->u.Database.contiguous)); + + /* Query GPU idle time. */ + gcmkONERROR( + gckKERNEL_QueryProcessDB(Kernel, + Interface->u.Database.processID, + !Interface->u.Database.validProcessID, + gcvDB_IDLE, + &Interface->u.Database.gpuIdle)); + break; + + case gcvHAL_VERSION: + Interface->u.Version.major = gcvVERSION_MAJOR; + Interface->u.Version.minor = gcvVERSION_MINOR; + Interface->u.Version.patch = gcvVERSION_PATCH; + Interface->u.Version.build = gcvVERSION_BUILD; +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, + "KERNEL version %d.%d.%d build %u %s %s", + gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, + gcvVERSION_BUILD, gcvVERSION_DATE, gcvVERSION_TIME); +#endif + break; + + case gcvHAL_CHIP_INFO: + /* Only if not support multi-core */ + Interface->u.ChipInfo.count = 1; + Interface->u.ChipInfo.types[0] = Kernel->hardware->type; + break; + + case gcvHAL_ATTACH: + /* Attach user process. */ + gcmkONERROR( + gckCOMMAND_Attach(Kernel->command, + &Interface->u.Attach.context, + &Interface->u.Attach.stateCount, + processID)); + + gcmkVERIFY_OK( + gckKERNEL_AddProcessDB(Kernel, + processID, gcvDB_CONTEXT, + Interface->u.Attach.context, + gcvNULL, + 0)); + break; + + case gcvHAL_DETACH: + /* Detach user process. */ + gcmkONERROR( + gckCOMMAND_Detach(Kernel->command, + Interface->u.Detach.context)); + + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(Kernel, + processID, gcvDB_CONTEXT, + Interface->u.Detach.context)); + break; + + case gcvHAL_COMPOSE: + /* Start composition. */ + gcmkONERROR( + gckEVENT_Compose(Kernel->eventObj, + &Interface->u.Compose)); + break; + + case gcvHAL_SET_TIMEOUT: + /* set timeOut value from user */ + gckKERNEL_SetTimeOut(Kernel, Interface->u.SetTimeOut.timeOut); + break; + +#if gcdFRAME_DB + case gcvHAL_GET_FRAME_INFO: + gcmkONERROR(gckHARDWARE_GetFrameInfo( + Kernel->hardware, + Interface->u.GetFrameInfo.frameInfo)); + break; +#endif + + case gcvHAL_GET_SHARED_INFO: + if (Interface->u.GetSharedInfo.dataId != 0) + { + gcmkONERROR(gckKERNEL_FindProcessDB(Kernel, + Interface->u.GetSharedInfo.pid, + 0, + gcvDB_SHARED_INFO, + gcmINT2PTR(Interface->u.GetSharedInfo.dataId), + &record)); + + /* find a record in db, check size */ + if (record.bytes != Interface->u.GetSharedInfo.size) + { + /* Size change is not allowed */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + + /* fetch data */ + gcmkONERROR(gckOS_CopyToUserData( + Kernel->os, + record.physical, + Interface->u.GetSharedInfo.data, + Interface->u.GetSharedInfo.size + )); + + } + + if ((node = Interface->u.GetSharedInfo.node) != gcvNULL) + { + switch (Interface->u.GetSharedInfo.infoType) + { + case gcvVIDMEM_INFO_GENERIC: + { /* Generic data stored */ + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + data = &node->VidMem.sharedInfo; + + } + else + { + data = &node->Virtual.sharedInfo; + } + + gcmkONERROR(gckOS_CopyToUserData( + Kernel->os, + data, + Interface->u.GetSharedInfo.nodeData, + sizeof(gcsVIDMEM_NODE_SHARED_INFO) + )); + } + break; + + case gcvVIDMEM_INFO_DIRTY_RECTANGLE: + { /* Dirty rectangle stored */ + gcsVIDMEM_NODE_SHARED_INFO *storedSharedInfo; + gcsVIDMEM_NODE_SHARED_INFO alignedSharedInfo; + + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + storedSharedInfo = &node->VidMem.sharedInfo; + } + else + { + storedSharedInfo = &node->Virtual.sharedInfo; + } + + /* Stored shared info holds the unaligned dirty rectangle. + Align it first. */ + + /* Hardware requires 64-byte aligned address, and 16x4 pixel aligned rectsize. + We simply align to 32 pixels which covers both 16- and 32-bpp formats. */ + + /* Make sure we have a legit rectangle. */ + gcmkASSERT((storedSharedInfo->RectSize.width != 0) && (storedSharedInfo->RectSize.height != 0)); + + alignedSharedInfo.SrcOrigin.x = gcmALIGN_BASE(storedSharedInfo->SrcOrigin.x, 32); + alignedSharedInfo.RectSize.width = gcmALIGN((storedSharedInfo->RectSize.width + (storedSharedInfo->SrcOrigin.x - alignedSharedInfo.SrcOrigin.x)), 16); + + alignedSharedInfo.SrcOrigin.y = gcmALIGN_BASE(storedSharedInfo->SrcOrigin.y, 4); + alignedSharedInfo.RectSize.height = gcmALIGN((storedSharedInfo->RectSize.height + (storedSharedInfo->SrcOrigin.y - alignedSharedInfo.SrcOrigin.y)), 4); + + gcmkONERROR(gckOS_CopyToUserData( + Kernel->os, + &alignedSharedInfo, + Interface->u.GetSharedInfo.nodeData, + sizeof(gcsVIDMEM_NODE_SHARED_INFO) + )); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, + "Node = %p, unaligned rectangle (l=%d, t=%d, w=%d, h=%d) aligned to (l=%d, t=%d, w=%d, h=%d)", node, + storedSharedInfo->SrcOrigin.x, storedSharedInfo->SrcOrigin.y, + storedSharedInfo->RectSize.width, storedSharedInfo->RectSize.height, + alignedSharedInfo.SrcOrigin.x, alignedSharedInfo.SrcOrigin.y, + alignedSharedInfo.RectSize.width, alignedSharedInfo.RectSize.height); + + /* Rectangle */ + storedSharedInfo->SrcOrigin.x = + storedSharedInfo->SrcOrigin.y = + storedSharedInfo->RectSize.width = + storedSharedInfo->RectSize.height = 0; + } + break; + } + } + break; + + case gcvHAL_SET_SHARED_INFO: + if (Interface->u.SetSharedInfo.dataId != 0) + { + status = gckKERNEL_FindProcessDB(Kernel, processID, 0, + gcvDB_SHARED_INFO, + gcmINT2PTR(Interface->u.SetSharedInfo.dataId), + &record); + + if (status == gcvSTATUS_INVALID_DATA) + { + /* private data has not been created yet */ + /* Note: we count on DestoryProcessDB to free it */ + gcmkONERROR(gckOS_AllocateMemory( + Kernel->os, + Interface->u.SetSharedInfo.size, + &data + )); + + gcmkONERROR( + gckKERNEL_AddProcessDB(Kernel, processID, + gcvDB_SHARED_INFO, + gcmINT2PTR(Interface->u.SetSharedInfo.dataId), + data, + Interface->u.SetSharedInfo.size + )); + } + else + { + /* bail on other errors */ + gcmkONERROR(status); + + /* find a record in db, check size */ + if (record.bytes != Interface->u.SetSharedInfo.size) + { + /* Size change is not allowed */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + + /* get storage address */ + data = record.physical; + } + + gcmkONERROR(gckOS_CopyFromUserData( + Kernel->os, + data, + Interface->u.SetSharedInfo.data, + Interface->u.SetSharedInfo.size + )); + } + + if ((node = Interface->u.SetSharedInfo.node) != gcvNULL) + { + switch (Interface->u.SetSharedInfo.infoType) + { + case gcvVIDMEM_INFO_GENERIC: + { /* Generic data stored */ + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + data = &node->VidMem.sharedInfo; + } + else + { + data = &node->Virtual.sharedInfo; + } + + gcmkONERROR(gckOS_CopyFromUserData( + Kernel->os, + data, + Interface->u.SetSharedInfo.nodeData, + sizeof(gcsVIDMEM_NODE_SHARED_INFO) + )); + } + break; + + case gcvVIDMEM_INFO_DIRTY_RECTANGLE: + { /* Dirty rectangle stored */ + gcsVIDMEM_NODE_SHARED_INFO newSharedInfo; + gcsVIDMEM_NODE_SHARED_INFO *currentSharedInfo; + gctINT dirtyX, dirtyY, right, bottom; + + /* Expand the dirty rectangle stored in the node to include the rectangle passed in. */ + gcmkONERROR(gckOS_CopyFromUserData( + Kernel->os, + &newSharedInfo, + Interface->u.SetSharedInfo.nodeData, + gcmSIZEOF(gcsVIDMEM_NODE_SHARED_INFO) + )); + + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + currentSharedInfo = &node->VidMem.sharedInfo; + } + else + { + currentSharedInfo = &node->Virtual.sharedInfo; + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "Node = %p Stored rectangle (l=%d, t=%d, w=%d, h=%d)", node, + currentSharedInfo->SrcOrigin.x, currentSharedInfo->SrcOrigin.y, + currentSharedInfo->RectSize.width, currentSharedInfo->RectSize.height); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "To combine with (l=%d, t=%d, w=%d, h=%d)", + newSharedInfo.SrcOrigin.x, newSharedInfo.SrcOrigin.y, + newSharedInfo.RectSize.width, newSharedInfo.RectSize.height); + + if ((currentSharedInfo->RectSize.width == 0) || (currentSharedInfo->RectSize.height == 0)) + { /* Setting it for the first time */ + currentSharedInfo->SrcOrigin.x = newSharedInfo.SrcOrigin.x; + currentSharedInfo->SrcOrigin.y = newSharedInfo.SrcOrigin.y; + currentSharedInfo->RectSize.width = newSharedInfo.RectSize.width; + currentSharedInfo->RectSize.height = newSharedInfo.RectSize.height; + } + else + { + /* Expand the stored rectangle to include newly locked rectangle */ + dirtyX = (newSharedInfo.SrcOrigin.x < currentSharedInfo->SrcOrigin.x) ? newSharedInfo.SrcOrigin.x : currentSharedInfo->SrcOrigin.x; + right = gcmMAX((currentSharedInfo->SrcOrigin.x + currentSharedInfo->RectSize.width), (newSharedInfo.SrcOrigin.x + newSharedInfo.RectSize.width)); + currentSharedInfo->RectSize.width = right - dirtyX; + currentSharedInfo->SrcOrigin.x = dirtyX; + + dirtyY = (newSharedInfo.SrcOrigin.y < currentSharedInfo->SrcOrigin.y) ? newSharedInfo.SrcOrigin.y : currentSharedInfo->SrcOrigin.y; + bottom = gcmMAX((currentSharedInfo->SrcOrigin.y + currentSharedInfo->RectSize.height), (newSharedInfo.SrcOrigin.y + newSharedInfo.RectSize.height)); + currentSharedInfo->RectSize.height = bottom - dirtyY; + currentSharedInfo->SrcOrigin.y = dirtyY; + } + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_KERNEL, "Combined rectangle (l=%d, t=%d, w=%d, h=%d)", + currentSharedInfo->SrcOrigin.x, currentSharedInfo->SrcOrigin.y, + currentSharedInfo->RectSize.width, currentSharedInfo->RectSize.height); + } + break; + } + } + + 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(Kernel, + Interface->u.LockVideoMemory.node, + gcvSURF_TYPE_UNKNOWN, + &asynchronous)); + + if (gcvTRUE == asynchronous) + { + /* Bottom Half */ + gcmkVERIFY_OK( + gckVIDMEM_Unlock(Kernel, + Interface->u.LockVideoMemory.node, + gcvSURF_TYPE_UNKNOWN, + gcvNULL)); + } + } + } + +#if QNX_SINGLE_THREADED_DEBUGGING + gckOS_ReleaseMutex(Kernel->os, Kernel->debugMutex); +#endif + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_AttachProcess +** +** Attach or detach a process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL Attach +** gcvTRUE if a new process gets attached or gcFALSE when a process +** gets detatched. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_AttachProcess( + IN gckKERNEL Kernel, + IN gctBOOL Attach + ) +{ + gceSTATUS status; + gctUINT32 processID; + + gcmkHEADER_ARG("Kernel=0x%x Attach=%d", Kernel, Attach); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Get current process ID. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + + gcmkONERROR(gckKERNEL_AttachProcessEx(Kernel, Attach, processID)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_AttachProcessEx +** +** Attach or detach a process with the given PID. Can be paired with gckKERNEL_AttachProcess +** provided the programmer is aware of the consequences. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL Attach +** gcvTRUE if a new process gets attached or gcFALSE when a process +** gets detatched. +** +** gctUINT32 PID +** PID of the process to attach or detach. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_AttachProcessEx( + IN gckKERNEL Kernel, + IN gctBOOL Attach, + IN gctUINT32 PID + ) +{ + gceSTATUS status; + gctINT32 old; + + gcmkHEADER_ARG("Kernel=0x%x Attach=%d PID=%d", Kernel, Attach, PID); + + /* 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) + { +#if gcdENABLE_VG + if (Kernel->vg == gcvNULL) +#endif + { + gcmkONERROR(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_FIRST_PROCESS)); + } + } + + if (Kernel->dbCreated) + { + /* Create the process database. */ + gcmkONERROR(gckKERNEL_CreateProcessDB(Kernel, PID)); + } + } + else + { + if (Kernel->dbCreated) + { + /* Clean up the process database. */ + gcmkONERROR(gckKERNEL_DestroyProcessDB(Kernel, PID)); + + /* Save the last know process ID. */ + Kernel->db->lastProcessID = PID; + } + + /* Decrement the number of clients attached. */ + gcmkONERROR( + gckOS_AtomDecrement(Kernel->os, Kernel->atomClients, &old)); + + if (old == 1) + { +#if gcdENABLE_VG + if (Kernel->vg == gcvNULL) +#endif + { + /* Last client detached, switch to SUSPEND power state. */ + gcmkONERROR(gckOS_Broadcast(Kernel->os, + Kernel->hardware, + gcvBROADCAST_LAST_PROCESS)); + } + + /* Flush the debug cache. */ + gcmkDEBUGFLUSH(~0U); + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gcskSECURE_CACHE_PTR Cache, + IN OUT gctPOINTER * Data + ) +{ + gceSTATUS status; + static gctBOOL baseAddressValid = gcvFALSE; + static gctUINT32 baseAddress; + gctBOOL needBase; + gcskLOGICAL_CACHE_PTR slot; + + gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x *Data=0x%x", + Kernel, Cache, gcmOPT_POINTER(Data)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + if (!baseAddressValid) + { + /* Get base address. */ + gcmkONERROR(gckHARDWARE_GetBaseAddress(Kernel->hardware, &baseAddress)); + + baseAddressValid = gcvTRUE; + } + + /* Does this state load need a base address? */ + gcmkONERROR(gckHARDWARE_NeedBaseAddress(Kernel->hardware, + ((gctUINT32_PTR) Data)[-1], + &needBase)); + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU + { + gcskLOGICAL_CACHE_PTR next; + gctINT i; + + /* Walk all used cache slots. */ + for (i = 1, slot = Cache->cache[0].next, next = gcvNULL; + (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL); + ++i, slot = slot->next + ) + { + if (slot->logical == *Data) + { + /* Bail out. */ + next = slot; + break; + } + } + + /* See if we had a miss. */ + if (next == gcvNULL) + { + /* Use the tail of the cache. */ + slot = Cache->cache[0].prev; + + /* Initialize the cache line. */ + slot->logical = *Data; + + /* Map the logical address to a DMA address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma)); + } + + /* Move slot to head of list. */ + if (slot != Cache->cache[0].next) + { + /* Unlink. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Move to head of chain. */ + slot->prev = &Cache->cache[0]; + slot->next = Cache->cache[0].next; + slot->prev->next = slot; + slot->next->prev = slot; + } + } +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR + { + gctINT i; + gcskLOGICAL_CACHE_PTR next = gcvNULL; + gcskLOGICAL_CACHE_PTR oldestSlot = gcvNULL; + slot = gcvNULL; + + if (Cache->cacheIndex != gcvNULL) + { + /* Walk the cache forwards. */ + for (i = 1, slot = Cache->cacheIndex; + (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL); + ++i, slot = slot->next) + { + if (slot->logical == *Data) + { + /* Bail out. */ + next = slot; + break; + } + + /* Determine age of this slot. */ + if ((oldestSlot == gcvNULL) + || (oldestSlot->stamp > slot->stamp) + ) + { + oldestSlot = slot; + } + } + + if (next == gcvNULL) + { + /* Walk the cache backwards. */ + for (slot = Cache->cacheIndex->prev; + (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL); + ++i, slot = slot->prev) + { + if (slot->logical == *Data) + { + /* Bail out. */ + next = slot; + break; + } + + /* Determine age of this slot. */ + if ((oldestSlot == gcvNULL) + || (oldestSlot->stamp > slot->stamp) + ) + { + oldestSlot = slot; + } + } + } + } + + /* See if we had a miss. */ + if (next == gcvNULL) + { + if (Cache->cacheFree != 0) + { + slot = &Cache->cache[Cache->cacheFree]; + gcmkASSERT(slot->logical == gcvNULL); + + ++ Cache->cacheFree; + if (Cache->cacheFree >= gcmCOUNTOF(Cache->cache)) + { + Cache->cacheFree = 0; + } + } + else + { + /* Use the oldest cache slot. */ + gcmkASSERT(oldestSlot != gcvNULL); + slot = oldestSlot; + + /* Unlink from the chain. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Append to the end. */ + slot->prev = Cache->cache[0].prev; + slot->next = &Cache->cache[0]; + slot->prev->next = slot; + slot->next->prev = slot; + } + + /* Initialize the cache line. */ + slot->logical = *Data; + + /* Map the logical address to a DMA address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma)); + } + + /* Save time stamp. */ + slot->stamp = ++ Cache->cacheStamp; + + /* Save current slot for next lookup. */ + Cache->cacheIndex = slot; + } +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + { + gctINT i; + gctUINT32 data = gcmPTR2INT(*Data); + gctUINT32 key, index; + gcskLOGICAL_CACHE_PTR hash; + + /* Generate a hash key. */ + key = (data >> 24) + (data >> 16) + (data >> 8) + data; + index = key % gcmCOUNTOF(Cache->hash); + + /* Get the hash entry. */ + hash = &Cache->hash[index]; + + for (slot = hash->nextHash, i = 0; + (slot != gcvNULL) && (i < gcdSECURE_CACHE_SLOTS); + slot = slot->nextHash, ++i + ) + { + if (slot->logical == (*Data)) + { + break; + } + } + + if (slot == gcvNULL) + { + /* Grab from the tail of the cache. */ + slot = Cache->cache[0].prev; + + /* Unlink slot from any hash table it is part of. */ + if (slot->prevHash != gcvNULL) + { + slot->prevHash->nextHash = slot->nextHash; + } + if (slot->nextHash != gcvNULL) + { + slot->nextHash->prevHash = slot->prevHash; + } + + /* Initialize the cache line. */ + slot->logical = *Data; + + /* Map the logical address to a DMA address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma)); + + if (hash->nextHash != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_KERNEL, + "Hash Collision: logical=0x%x key=0x%08x", + *Data, key); + } + + /* Insert the slot at the head of the hash list. */ + slot->nextHash = hash->nextHash; + if (slot->nextHash != gcvNULL) + { + slot->nextHash->prevHash = slot; + } + slot->prevHash = hash; + hash->nextHash = slot; + } + + /* Move slot to head of list. */ + if (slot != Cache->cache[0].next) + { + /* Unlink. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Move to head of chain. */ + slot->prev = &Cache->cache[0]; + slot->next = Cache->cache[0].next; + slot->prev->next = slot; + slot->next->prev = slot; + } + } +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE + { + gctUINT32 index = (gcmPTR2INT(*Data) % gcdSECURE_CACHE_SLOTS) + 1; + + /* Get cache slot. */ + slot = &Cache->cache[index]; + + /* Check for cache miss. */ + if (slot->logical != *Data) + { + /* Initialize the cache line. */ + slot->logical = *Data; + + /* Map the logical address to a DMA address. */ + gcmkONERROR( + gckOS_GetPhysicalAddress(Kernel->os, *Data, &slot->dma)); + } + } +#endif + + /* Return DMA address. */ + *Data = gcmINT2PTR(slot->dma + (needBase ? baseAddress : 0)); + + /* Success. */ + gcmkFOOTER_ARG("*Data=0x%08x", *Data); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_FlushTranslationCache( + IN gckKERNEL Kernel, + IN gcskSECURE_CACHE_PTR Cache, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gctINT i; + gcskLOGICAL_CACHE_PTR slot; + gctUINT8_PTR ptr; + + gcmkHEADER_ARG("Kernel=0x%x Cache=0x%x Logical=0x%x Bytes=%lu", + Kernel, Cache, Logical, Bytes); + + /* Do we need to flush the entire cache? */ + if (Logical == gcvNULL) + { + /* Clear all cache slots. */ + for (i = 1; i <= gcdSECURE_CACHE_SLOTS; ++i) + { + Cache->cache[i].logical = gcvNULL; + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + Cache->cache[i].nextHash = gcvNULL; + Cache->cache[i].prevHash = gcvNULL; +#endif +} + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + /* Zero the hash table. */ + for (i = 0; i < gcmCOUNTOF(Cache->hash); ++i) + { + Cache->hash[i].nextHash = gcvNULL; + } +#endif + + /* Reset the cache functionality. */ + Cache->cacheIndex = gcvNULL; + Cache->cacheFree = 1; + Cache->cacheStamp = 0; + } + + else + { + gctUINT8_PTR low = (gctUINT8_PTR) Logical; + gctUINT8_PTR high = low + Bytes; + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LRU + gcskLOGICAL_CACHE_PTR next; + + /* Walk all used cache slots. */ + for (i = 1, slot = Cache->cache[0].next; + (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL); + ++i, slot = next + ) + { + /* Save pointer to next slot. */ + next = slot->next; + + /* Test if this slot falls within the range to flush. */ + ptr = (gctUINT8_PTR) slot->logical; + if ((ptr >= low) && (ptr < high)) + { + /* Unlink slot. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Append slot to tail of cache. */ + slot->prev = Cache->cache[0].prev; + slot->next = &Cache->cache[0]; + slot->prev->next = slot; + slot->next->prev = slot; + + /* Mark slot as empty. */ + slot->logical = gcvNULL; + } + } + +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR + gcskLOGICAL_CACHE_PTR next; + + for (i = 1, slot = Cache->cache[0].next; + (i <= gcdSECURE_CACHE_SLOTS) && (slot->logical != gcvNULL); + ++i, slot = next) + { + /* Save pointer to next slot. */ + next = slot->next; + + /* Test if this slot falls within the range to flush. */ + ptr = (gctUINT8_PTR) slot->logical; + if ((ptr >= low) && (ptr < high)) + { + /* Test if this slot is the current slot. */ + if (slot == Cache->cacheIndex) + { + /* Move to next or previous slot. */ + Cache->cacheIndex = (slot->next->logical != gcvNULL) + ? slot->next + : (slot->prev->logical != gcvNULL) + ? slot->prev + : gcvNULL; + } + + /* Unlink slot from cache. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Insert slot to head of cache. */ + slot->prev = &Cache->cache[0]; + slot->next = Cache->cache[0].next; + slot->prev->next = slot; + slot->next->prev = slot; + + /* Mark slot as empty. */ + slot->logical = gcvNULL; + slot->stamp = 0; + } + } + +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + gctINT j; + gcskLOGICAL_CACHE_PTR hash, next; + + /* Walk all hash tables. */ + for (i = 0, hash = Cache->hash; + i < gcmCOUNTOF(Cache->hash); + ++i, ++hash) + { + /* Walk all slots in the hash. */ + for (j = 0, slot = hash->nextHash; + (j < gcdSECURE_CACHE_SLOTS) && (slot != gcvNULL); + ++j, slot = next) + { + /* Save pointer to next slot. */ + next = slot->next; + + /* Test if this slot falls within the range to flush. */ + ptr = (gctUINT8_PTR) slot->logical; + if ((ptr >= low) && (ptr < high)) + { + /* Unlink slot from hash table. */ + if (slot->prevHash == hash) + { + hash->nextHash = slot->nextHash; + } + else + { + slot->prevHash->nextHash = slot->nextHash; + } + + if (slot->nextHash != gcvNULL) + { + slot->nextHash->prevHash = slot->prevHash; + } + + /* Unlink slot from cache. */ + slot->prev->next = slot->next; + slot->next->prev = slot->prev; + + /* Append slot to tail of cache. */ + slot->prev = Cache->cache[0].prev; + slot->next = &Cache->cache[0]; + slot->prev->next = slot; + slot->next->prev = slot; + + /* Mark slot as empty. */ + slot->logical = gcvNULL; + slot->prevHash = gcvNULL; + slot->nextHash = gcvNULL; + } + } + } + +#elif gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_TABLE + gctUINT32 index; + + /* Loop while inside the range. */ + for (i = 1; (low < high) && (i <= gcdSECURE_CACHE_SLOTS); ++i) + { + /* Get index into cache for this range. */ + index = (gcmPTR2INT(low) % gcdSECURE_CACHE_SLOTS) + 1; + slot = &Cache->cache[index]; + + /* Test if this slot falls within the range to flush. */ + ptr = (gctUINT8_PTR) slot->logical; + if ((ptr >= low) && (ptr < high)) + { + /* Remove entry from cache. */ + slot->logical = gcvNULL; + } + + /* Next block. */ + low += gcdSECURE_CACHE_SLOTS; + } +#endif + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} +#endif + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ) +{ +#if gcdENABLE_RECOVERY + gceSTATUS status; + gckEVENT eventObj; + gckHARDWARE hardware; +#if gcdSECURE_USER + gctUINT32 processID; + gcskSECURE_CACHE_PTR cache; +#endif + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Validate the arguemnts. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Grab gckEVENT object. */ + eventObj = Kernel->eventObj; + gcmkVERIFY_OBJECT(eventObj, gcvOBJ_EVENT); + + /* Grab gckHARDWARE object. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Handle all outstanding events now. */ +#if gcdSMP + gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, ~0U)); +#else + eventObj->pending = ~0U; +#endif + gcmkONERROR(gckEVENT_Notify(eventObj, 1)); + + /* Again in case more events got submitted. */ +#if gcdSMP + gcmkONERROR(gckOS_AtomSet(Kernel->os, eventObj->pending, ~0U)); +#else + eventObj->pending = ~0U; +#endif + gcmkONERROR(gckEVENT_Notify(eventObj, 2)); + +#if gcdSECURE_USER + /* Flush the secure mapping cache. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + gcmkONERROR(gckKERNEL_GetProcessDBCache(Kernel, processID, &cache)); + gcmkONERROR(gckKERNEL_FlushTranslationCache(Kernel, cache, gcvNULL, 0)); +#endif + + /* Try issuing a soft reset for the GPU. */ + status = gckHARDWARE_Reset(hardware); + if (status == gcvSTATUS_NOT_SUPPORTED) + { + /* Switch to OFF power. The next submit should return the GPU to ON + ** state. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(hardware, + gcvPOWER_OFF_RECOVERY)); + } + else + { + /* Bail out on reset error. */ + gcmkONERROR(status); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +#else + return gcvSTATUS_OK; +#endif +} + +/******************************************************************************* +** +** gckKERNEL_OpenUserData +** +** Get access to the user data. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL NeedCopy +** The flag indicating whether or not the data should be copied. +** +** gctPOINTER StaticStorage +** Pointer to the kernel storage where the data is to be copied if +** NeedCopy is gcvTRUE. +** +** gctPOINTER UserPointer +** User pointer to the data. +** +** gctSIZE_T Size +** Size of the data. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to the kernel pointer that will be pointing to the data. +*/ +gceSTATUS +gckKERNEL_OpenUserData( + IN gckKERNEL Kernel, + IN gctBOOL NeedCopy, + IN gctPOINTER StaticStorage, + IN gctPOINTER UserPointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG( + "Kernel=0x%08X NeedCopy=%d StaticStorage=0x%08X " + "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X", + Kernel, NeedCopy, StaticStorage, UserPointer, Size, KernelPointer + ); + + /* Validate the arguemnts. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(!NeedCopy || (StaticStorage != gcvNULL)); + gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + + if (NeedCopy) + { + /* Copy the user data to the static storage. */ + gcmkONERROR(gckOS_CopyFromUserData( + Kernel->os, StaticStorage, UserPointer, Size + )); + + /* Set the kernel pointer. */ + * KernelPointer = StaticStorage; + } + else + { + gctPOINTER pointer = gcvNULL; + + /* Map the user pointer. */ + gcmkONERROR(gckOS_MapUserPointer( + Kernel->os, UserPointer, Size, &pointer + )); + + /* Set the kernel pointer. */ + * KernelPointer = pointer; + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_CloseUserData +** +** Release resources associated with the user data connection opened by +** gckKERNEL_OpenUserData. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL NeedCopy +** The flag indicating whether or not the data should be copied. +** +** gctBOOL FlushData +** If gcvTRUE, the data is written back to the user. +** +** gctPOINTER UserPointer +** User pointer to the data. +** +** gctSIZE_T Size +** Size of the data. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Kernel pointer to the data. +*/ +gceSTATUS +gckKERNEL_CloseUserData( + IN gckKERNEL Kernel, + IN gctBOOL NeedCopy, + IN gctBOOL FlushData, + IN gctPOINTER UserPointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctPOINTER pointer; + + gcmkHEADER_ARG( + "Kernel=0x%08X NeedCopy=%d FlushData=%d " + "UserPointer=0x%08X Size=%lu KernelPointer=0x%08X", + Kernel, NeedCopy, FlushData, UserPointer, Size, KernelPointer + ); + + /* Validate the arguemnts. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(UserPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + + /* Get a shortcut to the kernel pointer. */ + pointer = * KernelPointer; + + if (pointer != gcvNULL) + { + if (NeedCopy) + { + if (FlushData) + { + gcmkONERROR(gckOS_CopyToUserData( + Kernel->os, * KernelPointer, UserPointer, Size + )); + } + } + else + { + /* Unmap record from kernel memory. */ + gcmkONERROR(gckOS_UnmapUserPointer( + Kernel->os, + UserPointer, + Size, + * KernelPointer + )); + } + + /* Reset the kernel pointer. */ + * KernelPointer = gcvNULL; + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +void +gckKERNEL_SetTimeOut( + IN gckKERNEL Kernel, + IN gctUINT32 timeOut + ) +{ + gcmkHEADER_ARG("Kernel=0x%x timeOut=%d", Kernel, timeOut); +#if gcdGPU_TIMEOUT + Kernel->timeOut = timeOut; +#endif + gcmkFOOTER_NO(); +} + + + +/******************************************************************************* +***** Test Code **************************************************************** +*******************************************************************************/ + diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel.h b/kernel_drivers/v4/hal/kernel/gc_hal_kernel.h new file mode 100644 index 0000000..0be0c22 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel.h @@ -0,0 +1,789 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_h_ +#define __gc_hal_kernel_h_ + +#include "gc_hal.h" +#include "gc_hal_kernel_hardware.h" +#include "gc_hal_driver.h" + +#if gcdENABLE_VG +#include "gc_hal_kernel_vg.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/******************************************************************************* +***** New MMU Defination *******************************************************/ +#define gcdMMU_MTLB_SHIFT 22 +#define gcdMMU_STLB_4K_SHIFT 12 +#define gcdMMU_STLB_64K_SHIFT 16 + +#define gcdMMU_MTLB_BITS (32 - gcdMMU_MTLB_SHIFT) +#define gcdMMU_PAGE_4K_BITS gcdMMU_STLB_4K_SHIFT +#define gcdMMU_STLB_4K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_4K_BITS) +#define gcdMMU_PAGE_64K_BITS gcdMMU_STLB_64K_SHIFT +#define gcdMMU_STLB_64K_BITS (32 - gcdMMU_MTLB_BITS - gcdMMU_PAGE_64K_BITS) + +#define gcdMMU_MTLB_ENTRY_NUM (1 << gcdMMU_MTLB_BITS) +#define gcdMMU_MTLB_SIZE (gcdMMU_MTLB_ENTRY_NUM << 2) +#define gcdMMU_STLB_4K_ENTRY_NUM (1 << gcdMMU_STLB_4K_BITS) +#define gcdMMU_STLB_4K_SIZE (gcdMMU_STLB_4K_ENTRY_NUM << 2) +#define gcdMMU_PAGE_4K_SIZE (1 << gcdMMU_STLB_4K_SHIFT) +#define gcdMMU_STLB_64K_ENTRY_NUM (1 << gcdMMU_STLB_64K_BITS) +#define gcdMMU_STLB_64K_SIZE (gcdMMU_STLB_64K_ENTRY_NUM << 2) +#define gcdMMU_PAGE_64K_SIZE (1 << gcdMMU_STLB_64K_SHIFT) + +#define gcdMMU_MTLB_MASK (~((1U << gcdMMU_MTLB_SHIFT)-1)) +#define gcdMMU_STLB_4K_MASK ((~0U << gcdMMU_STLB_4K_SHIFT) ^ gcdMMU_MTLB_MASK) +#define gcdMMU_PAGE_4K_MASK (gcdMMU_PAGE_4K_SIZE - 1) +#define gcdMMU_STLB_64K_MASK ((~((1U << gcdMMU_STLB_64K_SHIFT)-1)) ^ gcdMMU_MTLB_MASK) +#define gcdMMU_PAGE_64K_MASK (gcdMMU_PAGE_64K_SIZE - 1) + +/******************************************************************************* +***** Process Secure Cache ****************************************************/ + +#define gcdSECURE_CACHE_LRU 1 +#define gcdSECURE_CACHE_LINEAR 2 +#define gcdSECURE_CACHE_HASH 3 +#define gcdSECURE_CACHE_TABLE 4 + +typedef struct _gcskLOGICAL_CACHE * gcskLOGICAL_CACHE_PTR; +typedef struct _gcskLOGICAL_CACHE gcskLOGICAL_CACHE; +struct _gcskLOGICAL_CACHE +{ + /* Logical address. */ + gctPOINTER logical; + + /* DMAable address. */ + gctUINT32 dma; + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + /* Pointer to the previous and next hash tables. */ + gcskLOGICAL_CACHE_PTR nextHash; + gcskLOGICAL_CACHE_PTR prevHash; +#endif + +#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE + /* Pointer to the previous and next slot. */ + gcskLOGICAL_CACHE_PTR next; + gcskLOGICAL_CACHE_PTR prev; +#endif + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_LINEAR + /* Time stamp. */ + gctUINT64 stamp; +#endif +}; + +typedef struct _gcskSECURE_CACHE * gcskSECURE_CACHE_PTR; +typedef struct _gcskSECURE_CACHE +{ + /* Cache memory. */ + gcskLOGICAL_CACHE cache[1 + gcdSECURE_CACHE_SLOTS]; + + /* Last known index for LINEAR mode. */ + gcskLOGICAL_CACHE_PTR cacheIndex; + + /* Current free slot for LINEAR mode. */ + gctUINT32 cacheFree; + + /* Time stamp for LINEAR mode. */ + gctUINT64 cacheStamp; + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + /* Hash table for HASH mode. */ + gcskLOGICAL_CACHE hash[256]; +#endif +} +gcskSECURE_CACHE; + +/******************************************************************************* +***** Process Database Management *********************************************/ + +typedef enum _gceDATABASE_TYPE +{ + gcvDB_VIDEO_MEMORY = 1, /* Video memory created. */ + gcvDB_NON_PAGED, /* Non paged memory. */ + gcvDB_CONTIGUOUS, /* Contiguous memory. */ + gcvDB_SIGNAL, /* Signal. */ + gcvDB_VIDEO_MEMORY_LOCKED, /* Video memory locked. */ + gcvDB_CONTEXT, /* Context */ + gcvDB_IDLE, /* GPU idle. */ + gcvDB_MAP_MEMORY, /* Map memory */ + gcvDB_SHARED_INFO, /* Private data */ + gcvDB_MAP_USER_MEMORY /* Map user memory */ +} +gceDATABASE_TYPE; + +typedef struct _gcsDATABASE_RECORD * gcsDATABASE_RECORD_PTR; +typedef struct _gcsDATABASE_RECORD +{ + /* Pointer to kernel. */ + gckKERNEL kernel; + + /* Pointer to next database record. */ + gcsDATABASE_RECORD_PTR next; + + /* Type of record. */ + gceDATABASE_TYPE type; + + /* Data for record. */ + gctPOINTER data; + gctPHYS_ADDR physical; + gctSIZE_T bytes; +} +gcsDATABASE_RECORD; + +typedef struct _gcsDATABASE * gcsDATABASE_PTR; +typedef struct _gcsDATABASE +{ + /* Pointer to next entry is hash list. */ + gcsDATABASE_PTR next; + gctSIZE_T slot; + + /* Process ID. */ + gctUINT32 processID; + + /* Sizes to query. */ + gcsDATABASE_COUNTERS vidMem; + gcsDATABASE_COUNTERS nonPaged; + gcsDATABASE_COUNTERS contiguous; + gcsDATABASE_COUNTERS mapUserMemory; + gcsDATABASE_COUNTERS mapMemory; + + /* Idle time management. */ + gctUINT64 lastIdle; + gctUINT64 idle; + + /* Pointer to database. */ + gcsDATABASE_RECORD_PTR list; + +#if gcdSECURE_USER + /* Secure cache. */ + gcskSECURE_CACHE cache; +#endif +} +gcsDATABASE; + +/* Create a process database that will contain all its allocations. */ +gceSTATUS +gckKERNEL_CreateProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID + ); + +/* Add a record to the process database. */ +gceSTATUS +gckKERNEL_AddProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Size + ); + +/* Remove a record to the process database. */ +gceSTATUS +gckKERNEL_RemoveProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer + ); + +/* Destroy the process database. */ +gceSTATUS +gckKERNEL_DestroyProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID + ); + +/* Find a record to the process database. */ +gceSTATUS +gckKERNEL_FindProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gctUINT32 ThreadID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer, + OUT gcsDATABASE_RECORD_PTR Record + ); + +/* Query the process database. */ +gceSTATUS +gckKERNEL_QueryProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gctBOOL LastProcessID, + IN gceDATABASE_TYPE Type, + OUT gcuDATABASE_INFO * Info + ); + +#if gcdSECURE_USER +/* Get secure cache from the process database. */ +gceSTATUS +gckKERNEL_GetProcessDBCache( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + OUT gcskSECURE_CACHE_PTR * Cache + ); +#endif + +/******************************************************************************* +********* Timer Management ****************************************************/ +typedef struct _gcsTIMER * gcsTIMER_PTR; +typedef struct _gcsTIMER +{ + /* Start and Stop time holders. */ + gctUINT64 startTime; + gctUINT64 stopTime; +} +gcsTIMER; + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + +/* gckDB object. */ +struct _gckDB +{ + /* Database management. */ + gcsDATABASE_PTR db[16]; + gctPOINTER dbMutex; + gcsDATABASE_PTR freeDatabase; + gcsDATABASE_RECORD_PTR freeRecord; + gcsDATABASE_PTR lastDatabase; + gctUINT32 lastProcessID; + gctUINT64 lastIdle; + gctUINT64 idleTime; + gctUINT64 lastSlowdown; + gctUINT64 lastSlowdownIdle; +}; + +/* gckKERNEL object. */ +struct _gckKERNEL +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Core */ + gceCORE core; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* Pointer to gckCOMMAND object. */ + gckCOMMAND command; + + /* Pointer to gckEVENT object. */ + gckEVENT eventObj; + + /* Pointer to context. */ + gctPOINTER context; + + /* Pointer to gckMMU object. */ + gckMMU mmu; + + /* Arom holding number of clients. */ + gctPOINTER atomClients; + +#if VIVANTE_PROFILER + /* Enable profiling */ + gctBOOL profileEnable; + + /* The profile file name */ + gctCHAR profileFileName[gcdMAX_PROFILE_FILE_NAME]; +#endif + +#ifdef QNX_SINGLE_THREADED_DEBUGGING + gctPOINTER debugMutex; +#endif + + /* Database management. */ + gckDB db; + gctBOOL dbCreated; + + /* Pointer to gckEVENT object. */ + gcsTIMER timers[8]; + gctUINT32 timeOut; + +#if gcdENABLE_VG + gckVGKERNEL vg; +#endif +}; + +/* gckCOMMAND object. */ +struct _gckCOMMAND +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to required object. */ + gckKERNEL kernel; + gckOS os; + + /* Number of bytes per page. */ + gctSIZE_T pageSize; + + /* Current pipe select. */ + gcePIPE_SELECT pipeSelect; + + /* Command queue running flag. */ + gctBOOL running; + + /* Idle flag and commit stamp. */ + gctBOOL idle; + gctUINT64 commitStamp; + + /* Command queue mutex. */ + gctPOINTER mutexQueue; + + /* Context switching mutex. */ + gctPOINTER mutexContext; + + /* Command queue power semaphore. */ + gctPOINTER powerSemaphore; + + /* Current command queue. */ + struct _gcskCOMMAND_QUEUE + { + gctSIGNAL signal; + gctPHYS_ADDR physical; + gctPOINTER logical; + } + queues[gcdCOMMAND_QUEUES]; + + gctPHYS_ADDR physical; + gctPOINTER logical; + gctUINT32 offset; + gctINT index; +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gctUINT wrapCount; +#endif + + /* The command queue is new. */ + gctBOOL newQueue; + + /* Context management. */ + gckCONTEXT currContext; + + /* Pointer to last WAIT command. */ + gctPHYS_ADDR waitPhysical; + gctPOINTER waitLogical; + gctSIZE_T waitSize; + + /* Command buffer alignment. */ + gctSIZE_T alignment; + gctSIZE_T reservedHead; + gctSIZE_T reservedTail; + + /* Commit counter. */ + gctPOINTER atomCommit; + + /* Kernel process ID. */ + gctUINT32 kernelProcessID; + + /* End Event signal. */ + gctSIGNAL endEventSignal; + +#if gcdSECURE_USER + /* Hint array copy buffer. */ + gctBOOL hintArrayAllocated; + gctUINT hintArraySize; + gctUINT32_PTR hintArray; +#endif +}; + +typedef struct _gcsEVENT * gcsEVENT_PTR; + +/* Structure holding one event to be processed. */ +typedef struct _gcsEVENT +{ + /* Pointer to next event in queue. */ + gcsEVENT_PTR next; + + /* Event information. */ + gcsHAL_INTERFACE info; + + /* Process ID owning the event. */ + gctUINT32 processID; + +#ifdef __QNXNTO__ + /* Kernel. */ + gckKERNEL kernel; +#endif +} +gcsEVENT; + +/* Structure holding a list of events to be processed by an interrupt. */ +typedef struct _gcsEVENT_QUEUE * gcsEVENT_QUEUE_PTR; +typedef struct _gcsEVENT_QUEUE +{ + /* Time stamp. */ + gctUINT64 stamp; + + /* Source of the event. */ + gceKERNEL_WHERE source; + + /* Pointer to head of event queue. */ + gcsEVENT_PTR head; + + /* Pointer to tail of event queue. */ + gcsEVENT_PTR tail; + + /* Next list of events. */ + gcsEVENT_QUEUE_PTR next; +} +gcsEVENT_QUEUE; + +/* + gcdREPO_LIST_COUNT defines the maximum number of event queues with different + hardware module sources that may coexist at the same time. Only two sources + are supported - gcvKERNEL_COMMAND and gcvKERNEL_PIXEL. gcvKERNEL_COMMAND + source is used only for managing the kernel command queue and is only issued + when the current command queue gets full. Since we commit event queues every + time we commit command buffers, in the worst case we can have up to three + pending event queues: + - gcvKERNEL_PIXEL + - gcvKERNEL_COMMAND (queue overflow) + - gcvKERNEL_PIXEL +*/ +#define gcdREPO_LIST_COUNT 3 + +/* gckEVENT object. */ +struct _gckEVENT +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to required objects. */ + gckOS os; + gckKERNEL kernel; + + /* Time stamp. */ + gctUINT64 stamp; + gctUINT64 lastCommitStamp; + + /* Queue mutex. */ + gctPOINTER eventQueueMutex; + + /* Array of event queues. */ + gcsEVENT_QUEUE queues[30]; + gctUINT8 lastID; + gctPOINTER freeAtom; + + /* Pending events. */ +#if gcdSMP + gctPOINTER pending; +#else + volatile gctUINT pending; +#endif + + /* List of free event structures and its mutex. */ + gcsEVENT_PTR freeEventList; + gctSIZE_T freeEventCount; + gctPOINTER freeEventMutex; + + /* Event queues. */ + gcsEVENT_QUEUE_PTR queueHead; + gcsEVENT_QUEUE_PTR queueTail; + gcsEVENT_QUEUE_PTR freeList; + gcsEVENT_QUEUE repoList[gcdREPO_LIST_COUNT]; + gctPOINTER eventListMutex; +}; + +/* Free all events belonging to a process. */ +gceSTATUS +gckEVENT_FreeProcess( + IN gckEVENT Event, + IN gctUINT32 ProcessID + ); + +gceSTATUS +gckEVENT_Stop( + IN gckEVENT Event, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Logical, + IN gctSIGNAL Signal, + IN OUT gctSIZE_T * waitSize + ); + +/* gcuVIDMEM_NODE structure. */ +typedef union _gcuVIDMEM_NODE +{ + /* Allocated from gckVIDMEM. */ + struct _gcsVIDMEM_NODE_VIDMEM + { + /* Owner of this node. */ + gckVIDMEM memory; + + /* Dual-linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + gcuVIDMEM_NODE_PTR prev; + + /* Dual linked list of free nodes. */ + gcuVIDMEM_NODE_PTR nextFree; + gcuVIDMEM_NODE_PTR prevFree; + + /* Information for this node. */ + gctUINT32 offset; + gctSIZE_T bytes; + gctUINT32 alignment; + +#ifdef __QNXNTO__ + /* Client/server vaddr (mapped using mmap_join). */ + gctPOINTER logical; +#endif + + /* Locked counter. */ + gctINT32 locked; + + /* Memory pool. */ + gcePOOL pool; + gctUINT32 physical; + + /* Process ID owning this memory. */ + gctUINT32 processID; + + /* Prevent compositor from freeing until client unlocks. */ + gctBOOL freePending; + + /* */ + gcsVIDMEM_NODE_SHARED_INFO sharedInfo; + +#if gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG + gctPOINTER kernelVirtual; +#endif + } + VidMem; + + /* Allocated from gckOS. */ + struct _gcsVIDMEM_NODE_VIRTUAL + { + /* Pointer to gckKERNEL object. */ + gckKERNEL kernel; + + /* Information for this node. */ + /* Contiguously allocated? */ + gctBOOL contiguous; + /* mdl record pointer... a kmalloc address. Process agnostic. */ + gctPHYS_ADDR physical; + gctSIZE_T bytes; + /* do_mmap_pgoff address... mapped per-process. */ + gctPOINTER logical; + + /* Page table information. */ + /* Used only when node is not contiguous */ + gctSIZE_T pageCount; + + /* Used only when node is not contiguous */ + gctPOINTER pageTables[gcdCORE_COUNT]; + /* Pointer to gckKERNEL object who lock this. */ + gckKERNEL lockKernels[gcdCORE_COUNT]; + /* Actual physical address */ + gctUINT32 addresses[gcdCORE_COUNT]; + + /* Mutex. */ + gctPOINTER mutex; + + /* Locked counter. */ + gctINT32 lockeds[gcdCORE_COUNT]; + +#ifdef __QNXNTO__ + /* Single linked list of nodes. */ + gcuVIDMEM_NODE_PTR next; + + /* Unlock pending flag. */ + gctBOOL unlockPendings[gcdCORE_COUNT]; + + /* Free pending flag. */ + gctBOOL freePending; +#endif + + /* Process ID owning this memory. */ + gctUINT32 processID; + + /* Owner process sets freed to true + * when it trys to free a locked + * node */ + gctBOOL freed; + + /* */ + gcsVIDMEM_NODE_SHARED_INFO sharedInfo; + } + Virtual; +} +gcuVIDMEM_NODE; + +/* gckVIDMEM object. */ +struct _gckVIDMEM +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Information for this video memory heap. */ + gctUINT32 baseAddress; + gctSIZE_T bytes; + gctSIZE_T freeBytes; + + /* Mapping for each type of surface. */ + gctINT mapping[gcvSURF_NUM_TYPES]; + + /* Sentinel nodes for up to 8 banks. */ + gcuVIDMEM_NODE sentinel[8]; + + /* Allocation threshold. */ + gctSIZE_T threshold; + + /* The heap mutex. */ + gctPOINTER mutex; + +#if gcdUSE_VIDMEM_PER_PID + /* The Pid this VidMem belongs to. */ + gctUINT32 pid; + + struct _gckVIDMEM* next; +#endif +}; + +/* gckMMU object. */ +struct _gckMMU +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckHARDWARE hardware; + + /* The page table mutex. */ + gctPOINTER pageTableMutex; + + /* Page table information. */ + gctSIZE_T pageTableSize; + gctPHYS_ADDR pageTablePhysical; + gctUINT32_PTR pageTableLogical; + gctUINT32 pageTableEntries; + + /* Master TLB information. */ + gctSIZE_T mtlbSize; + gctPHYS_ADDR mtlbPhysical; + gctUINT32_PTR mtlbLogical; + gctUINT32 mtlbEntries; + + /* Free entries. */ + gctUINT32 heapList; + gctBOOL freeNodes; + + gctPOINTER staticSTLB; + gctBOOL enabled; + + gctUINT32 dynamicMappingStart; + +#ifdef __QNXNTO__ + /* Single linked list of all allocated nodes. */ + gctPOINTER nodeMutex; + gcuVIDMEM_NODE_PTR nodeList; +#endif +}; + +gceSTATUS +gckKERNEL_AttachProcess( + IN gckKERNEL Kernel, + IN gctBOOL Attach + ); + +gceSTATUS +gckKERNEL_AttachProcessEx( + IN gckKERNEL Kernel, + IN gctBOOL Attach, + IN gctUINT32 PID + ); + +#if gcdSECURE_USER +gceSTATUS +gckKERNEL_MapLogicalToPhysical( + IN gckKERNEL Kernel, + IN gcskSECURE_CACHE_PTR Cache, + IN OUT gctPOINTER * Data + ); + +gceSTATUS +gckKERNEL_FlushTranslationCache( + IN gckKERNEL Kernel, + IN gcskSECURE_CACHE_PTR Cache, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); +#endif + +gceSTATUS +gckHARDWARE_QueryIdle( + IN gckHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ); + +/******************************************************************************\ +******************************* gckCONTEXT Object ******************************* +\******************************************************************************/ + +gceSTATUS +gckCONTEXT_Construct( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT32 ProcessID, + OUT gckCONTEXT * Context + ); + +gceSTATUS +gckCONTEXT_Destroy( + IN gckCONTEXT Context + ); + +gceSTATUS +gckCONTEXT_Update( + IN gckCONTEXT Context, + IN gctUINT32 ProcessID, + IN gcsSTATE_DELTA_PTR StateDelta + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command.c new file mode 100644 index 0000000..572c728 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command.c @@ -0,0 +1,2631 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_kernel_context.h" + +#ifdef __QNXNTO__ +#include <sys/slog.h> +#endif + +#define _GC_OBJ_ZONE gcvZONE_COMMAND + +/* When enabled, extra messages needed by the dump parser are left out. */ +#define gcdSIMPLE_COMMAND_DUMP 1 + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +/******************************************************************************* +** +** _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 + ) +{ + gceSTATUS status; + gctINT currentIndex, newIndex; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Switch to the next command buffer. */ + currentIndex = Command->index; + newIndex = (currentIndex + 1) % gcdCOMMAND_QUEUES; + + /* Wait for availability. */ +#if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP + gcmkPRINT("@[kernel.waitsignal]"); +#endif + + gcmkONERROR(gckOS_WaitSignal( + Command->os, + Command->queues[newIndex].signal, + gcvINFINITE + )); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + if (newIndex < currentIndex) + { + Command->wrapCount += 1; + + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_COMMAND, + 2 * 4, + "%s(%d): queue array wrapped around.\n", + __FUNCTION__, __LINE__ + ); + } + + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_COMMAND, + 3 * 4, + "%s(%d): total queue wrap arounds %d.\n", + __FUNCTION__, __LINE__, Command->wrapCount + ); + + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_COMMAND, + 3 * 4, + "%s(%d): switched to queue %d.\n", + __FUNCTION__, __LINE__, newIndex + ); +#endif + + /* Update gckCOMMAND object with new command queue. */ + Command->index = newIndex; + Command->newQueue = gcvTRUE; + Command->logical = Command->queues[newIndex].logical; + Command->offset = 0; + + gcmkONERROR( + gckOS_GetPhysicalAddress( + Command->os, + Command->logical, + (gctUINT32 *) &Command->physical + )); + + if (currentIndex != -1) + { + /* Mark the command queue as available. */ + gcmkONERROR(gckEVENT_Signal( + Command->kernel->eventObj, + Command->queues[currentIndex].signal, + gcvKERNEL_COMMAND + )); + } + + /* Success. */ + gcmkFOOTER_ARG("Command->index=%d", Command->index); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_IncrementCommitAtom( + IN gckCOMMAND Command, + IN gctBOOL Increment + ) +{ + gceSTATUS status; + gckHARDWARE hardware; + gctINT32 atomValue; + gctBOOL powerAcquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Extract the gckHARDWARE and gckEVENT objects. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Grab the power mutex. */ + gcmkONERROR(gckOS_AcquireMutex( + Command->os, hardware->powerMutex, gcvINFINITE + )); + powerAcquired = gcvTRUE; + + /* Increment the commit atom. */ + if (Increment) + { + gcmkONERROR(gckOS_AtomIncrement( + Command->os, Command->atomCommit, &atomValue + )); + } + else + { + gcmkONERROR(gckOS_AtomDecrement( + Command->os, Command->atomCommit, &atomValue + )); + } + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex( + Command->os, hardware->powerMutex + )); + powerAcquired = gcvFALSE; + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (powerAcquired) + { + /* Release the power mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex( + Command->os, hardware->powerMutex + )); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +static gceSTATUS +_ProcessHints( + IN gckCOMMAND Command, + IN gctUINT32 ProcessID, + IN gcoCMDBUF CommandBuffer + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gckKERNEL kernel; + gctBOOL needCopy = gcvFALSE; + gcskSECURE_CACHE_PTR cache; + gctUINT8_PTR commandBufferLogical; + gctUINT8_PTR hintedData; + gctUINT32_PTR hintArray; + gctUINT i, hintCount; + + gcmkHEADER_ARG( + "Command=0x%08X ProcessID=%d CommandBuffer=0x%08X", + Command, ProcessID, CommandBuffer + ); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Reset state array pointer. */ + hintArray = gcvNULL; + + /* Get the kernel object. */ + kernel = Command->kernel; + + /* Get the cache form the database. */ + gcmkONERROR(gckKERNEL_GetProcessDBCache(kernel, ProcessID, &cache)); + + /* Determine the start of the command buffer. */ + commandBufferLogical + = (gctUINT8_PTR) CommandBuffer->logical + + CommandBuffer->startOffset; + + /* Determine the number of records in the state array. */ + hintCount = CommandBuffer->hintArrayTail - CommandBuffer->hintArray; + + /* Check wehther we need to copy the structures or not. */ + gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy)); + + /* Get access to the state array. */ + if (needCopy) + { + gctUINT copySize; + + if (Command->hintArrayAllocated && + (Command->hintArraySize < CommandBuffer->hintArraySize)) + { + gcmkONERROR(gcmkOS_SAFE_FREE(Command->os, Command->hintArray)); + Command->hintArraySize = gcvFALSE; + } + + if (!Command->hintArrayAllocated) + { + gctPOINTER pointer = gcvNULL; + + gcmkONERROR(gckOS_Allocate( + Command->os, + CommandBuffer->hintArraySize, + &pointer + )); + + Command->hintArray = pointer; + Command->hintArrayAllocated = gcvTRUE; + Command->hintArraySize = CommandBuffer->hintArraySize; + } + + hintArray = Command->hintArray; + copySize = hintCount * gcmSIZEOF(gctUINT32); + + gcmkONERROR(gckOS_CopyFromUserData( + Command->os, + hintArray, + CommandBuffer->hintArray, + copySize + )); + } + else + { + gctPOINTER pointer = gcvNULL; + + gcmkONERROR(gckOS_MapUserPointer( + Command->os, + CommandBuffer->hintArray, + CommandBuffer->hintArraySize, + &pointer + )); + + hintArray = pointer; + } + + /* Scan through the buffer. */ + for (i = 0; i < hintCount; i += 1) + { + /* Determine the location of the hinted data. */ + hintedData = commandBufferLogical + hintArray[i]; + + /* Map handle into physical address. */ + gcmkONERROR(gckKERNEL_MapLogicalToPhysical( + kernel, cache, (gctPOINTER) hintedData + )); + } + +OnError: + /* Get access to the state array. */ + if (!needCopy && (hintArray != gcvNULL)) + { + gcmkVERIFY_OK(gckOS_UnmapUserPointer( + Command->os, + CommandBuffer->hintArray, + CommandBuffer->hintArraySize, + hintArray + )); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif + +static gceSTATUS +_FlushMMU( + IN gckCOMMAND Command + ) +{ + gceSTATUS status; + gctUINT32 oldValue; + gckHARDWARE hardware = Command->kernel->hardware; + + gcmkONERROR(gckOS_AtomicExchange(Command->os, + hardware->pageTableDirty, + 0, + &oldValue)); + + if (oldValue) + { + /* Page Table is upated, flush mmu before commit. */ + gcmkONERROR(gckHARDWARE_FlushMMU(hardware)); + } + + return gcvSTATUS_OK; +OnError: + return status; +} + +/******************************************************************************\ +****************************** gckCOMMAND API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckCOMMAND_Construct +** +** Construct a new gckCOMMAND object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckCOMMAND * Command +** Pointer to a variable that will hold the pointer to the gckCOMMAND +** object. +*/ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ) +{ + gckOS os; + gckCOMMAND command = gcvNULL; + gceSTATUS status; + gctINT i; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Command != gcvNULL); + + /* Extract the gckOS object. */ + os = Kernel->os; + + /* Allocate the gckCOMMAND structure. */ + gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckCOMMAND), &pointer)); + command = pointer; + + /* Reset the entire object. */ + gcmkONERROR(gckOS_ZeroMemory(command, gcmSIZEOF(struct _gckCOMMAND))); + + /* Initialize the gckCOMMAND object.*/ + command->object.type = gcvOBJ_COMMAND; + command->kernel = Kernel; + command->os = os; + + /* Get the command buffer requirements. */ + gcmkONERROR(gckHARDWARE_QueryCommandBuffer( + Kernel->hardware, + &command->alignment, + &command->reservedHead, + &command->reservedTail + )); + + /* Create the command queue mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &command->mutexQueue)); + + /* Create the context switching mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &command->mutexContext)); + + /* Create the power management semaphore. */ + gcmkONERROR(gckOS_CreateSemaphore(os, &command->powerSemaphore)); + + /* Create the commit atom. */ + gcmkONERROR(gckOS_AtomConstruct(os, &command->atomCommit)); + + /* Get the page size from teh OS. */ + gcmkONERROR(gckOS_GetPageSize(os, &command->pageSize)); + + /* Get process ID. */ + gcmkONERROR(gckOS_GetProcessID(&command->kernelProcessID)); + + /* Set hardware to pipe 0. */ + command->pipeSelect = gcvPIPE_INVALID; + + /* Pre-allocate the command queues. */ + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkONERROR(gckOS_AllocateNonPagedMemory( + os, + gcvFALSE, + &command->pageSize, + &command->queues[i].physical, + &command->queues[i].logical + )); + + gcmkONERROR(gckOS_CreateSignal( + os, gcvFALSE, &command->queues[i].signal + )); + + gcmkONERROR(gckOS_Signal( + os, command->queues[i].signal, gcvTRUE + )); + } + + /* No command queue in use yet. */ + command->index = -1; + command->logical = gcvNULL; + command->newQueue = gcvFALSE; + + /* Command is not yet running. */ + command->running = gcvFALSE; + + /* Command queue is idle. */ + command->idle = gcvTRUE; + + /* Commit stamp is zero. */ + command->commitStamp = 0; + + /* END event signal not created. */ + command->endEventSignal = gcvNULL; + + /* Return pointer to the gckCOMMAND object. */ + *Command = command; + + /* Success. */ + gcmkFOOTER_ARG("*Command=0x%x", *Command); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (command != gcvNULL) + { + if (command->atomCommit != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(os, command->atomCommit)); + } + + if (command->powerSemaphore != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySemaphore(os, command->powerSemaphore)); + } + + if (command->mutexContext != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexContext)); + } + + if (command->mutexQueue != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, command->mutexQueue)); + } + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + if (command->queues[i].signal != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySignal( + os, command->queues[i].signal + )); + } + + if (command->queues[i].logical != gcvNULL) + { + gcmkVERIFY_OK(gckOS_FreeNonPagedMemory( + os, + command->pageSize, + command->queues[i].physical, + command->queues[i].logical + )); + } + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, command)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Destroy +** +** Destroy an gckCOMMAND object. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ) +{ + gctINT i; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Stop the command queue. */ + gcmkVERIFY_OK(gckCOMMAND_Stop(Command, gcvFALSE)); + + for (i = 0; i < gcdCOMMAND_QUEUES; ++i) + { + gcmkASSERT(Command->queues[i].signal != gcvNULL); + gcmkVERIFY_OK(gckOS_DestroySignal( + Command->os, Command->queues[i].signal + )); + + gcmkASSERT(Command->queues[i].logical != gcvNULL); + gcmkVERIFY_OK(gckOS_FreeNonPagedMemory( + Command->os, + Command->pageSize, + Command->queues[i].physical, + Command->queues[i].logical + )); + } + + /* END event signal. */ + if (Command->endEventSignal != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySignal( + Command->os, Command->endEventSignal + )); + } + + /* Delete the context switching mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexContext)); + + /* Delete the command queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Command->os, Command->mutexQueue)); + + /* Destroy the power management semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySemaphore(Command->os, Command->powerSemaphore)); + + /* Destroy the commit atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Command->os, Command->atomCommit)); + +#if gcdSECURE_USER + /* Free state array. */ + if (Command->hintArrayAllocated) + { + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, Command->hintArray)); + Command->hintArrayAllocated = gcvFALSE; + } +#endif + + /* Mark object as unknown. */ + Command->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckCOMMAND object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Command->os, Command)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckCOMMAND_EnterCommit +** +** Acquire command queue synchronization objects. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to destroy. +** +** gctBOOL FromPower +** Determines whether the call originates from inside the power +** management or not. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_EnterCommit( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ) +{ + gceSTATUS status; + gckHARDWARE hardware; + gctBOOL atomIncremented = gcvFALSE; + gctBOOL semaAcquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Extract the gckHARDWARE and gckEVENT objects. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + if (!FromPower) + { + /* Increment COMMIT atom to let power management know that a commit is + ** in progress. */ + gcmkONERROR(_IncrementCommitAtom(Command, gcvTRUE)); + atomIncremented = gcvTRUE; + + /* Notify the system the GPU has a commit. */ + gcmkONERROR(gckOS_Broadcast(Command->os, + hardware, + gcvBROADCAST_GPU_COMMIT)); + + /* Acquire the power management semaphore. */ + gcmkONERROR(gckOS_AcquireSemaphore(Command->os, + Command->powerSemaphore)); + semaAcquired = gcvTRUE; + } + + /* Grab the conmmand queue mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Command->os, + Command->mutexQueue, + gcvINFINITE)); + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (semaAcquired) + { + /* Release the power management semaphore. */ + gcmkVERIFY_OK(gckOS_ReleaseSemaphore( + Command->os, Command->powerSemaphore + )); + } + + if (atomIncremented) + { + /* Decrement the commit atom. */ + gcmkVERIFY_OK(_IncrementCommitAtom( + Command, gcvFALSE + )); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_ExitCommit +** +** Release command queue synchronization objects. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to destroy. +** +** gctBOOL FromPower +** Determines whether the call originates from inside the power +** management or not. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_ExitCommit( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Release the power mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexQueue)); + + if (!FromPower) + { + /* Release the power management semaphore. */ + gcmkONERROR(gckOS_ReleaseSemaphore(Command->os, + Command->powerSemaphore)); + + /* Decrement the commit atom. */ + gcmkONERROR(_IncrementCommitAtom(Command, gcvFALSE)); + } + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Start +** +** Start up the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to start. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ) +{ + gceSTATUS status; + gckHARDWARE hardware; + gctUINT32 waitOffset; + gctSIZE_T waitLinkBytes; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (Command->running) + { + /* Command queue already running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + if (Command->logical == gcvNULL) + { + /* Start at beginning of a new queue. */ + gcmkONERROR(_NewQueue(Command)); + } + + /* Start at beginning of page. */ + Command->offset = 0; + + /* Set abvailable number of bytes for WAIT/LINK command sequence. */ + waitLinkBytes = Command->pageSize; + + /* Append WAIT/LINK. */ + gcmkONERROR(gckHARDWARE_WaitLink( + hardware, + Command->logical, + 0, + &waitLinkBytes, + &waitOffset, + &Command->waitSize + )); + + Command->waitLogical = (gctUINT8_PTR) Command->logical + waitOffset; + Command->waitPhysical = (gctUINT8_PTR) Command->physical + waitOffset; + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache for the wait/link. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + Command->physical, + Command->logical, + waitLinkBytes + )); +#endif + + /* Adjust offset. */ + Command->offset = waitLinkBytes; + Command->newQueue = gcvFALSE; + + /* Enable command processor. */ +#ifdef __QNXNTO__ + gcmkONERROR(gckHARDWARE_Execute( + hardware, + Command->logical, + Command->physical, + gcvTRUE, + waitLinkBytes + )); +#else + gcmkONERROR(gckHARDWARE_Execute( + hardware, + Command->logical, + waitLinkBytes + )); +#endif + + /* Command queue is running. */ + Command->running = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Stop +** +** Stop the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object to stop. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command, + IN gctBOOL FromRecovery + ) +{ + gckHARDWARE hardware; + gceSTATUS status; + gctUINT32 idle; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (!Command->running) + { + /* Command queue is not running. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract the gckHARDWARE object. */ + hardware = Command->kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + if (gckHARDWARE_IsFeatureAvailable(hardware, + gcvFEATURE_END_EVENT) == gcvSTATUS_TRUE) + { + /* Allocate the signal. */ + if (Command->endEventSignal == gcvNULL) + { + gcmkONERROR(gckOS_CreateSignal(Command->os, + gcvTRUE, + &Command->endEventSignal)); + } + + /* Append the END EVENT command to trigger the signal. */ + gcmkONERROR(gckEVENT_Stop(Command->kernel->eventObj, + Command->kernelProcessID, + Command->waitPhysical, + Command->waitLogical, + Command->endEventSignal, + &Command->waitSize)); + } + else + { + /* Replace last WAIT with END. */ + gcmkONERROR(gckHARDWARE_End( + hardware, Command->waitLogical, &Command->waitSize + )); + + /* Update queue tail pointer. */ + gcmkONERROR(gckHARDWARE_UpdateQueueTail(Command->kernel->hardware, + Command->logical, + Command->offset)); + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache for the END. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + Command->waitPhysical, + Command->waitLogical, + Command->waitSize + )); +#endif + + /* Wait for idle. */ + gcmkONERROR(gckHARDWARE_GetIdle(hardware, !FromRecovery, &idle)); + } + + /* Command queue is no longer running. */ + Command->running = gcvFALSE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Commit +** +** Commit a command buffer to the command queue. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to a gckCOMMAND object. +** +** gckCONTEXT Context +** Pointer to a gckCONTEXT object. +** +** gcoCMDBUF CommandBuffer +** Pointer to a gcoCMDBUF object. +** +** gcsSTATE_DELTA_PTR StateDelta +** Pointer to the state delta. +** +** gctUINT32 ProcessID +** Current process ID. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Commit( + IN gckCOMMAND Command, + IN gckCONTEXT Context, + IN gcoCMDBUF CommandBuffer, + IN gcsSTATE_DELTA_PTR StateDelta, + IN gcsQUEUE_PTR EventQueue, + IN gctUINT32 ProcessID + ) +{ + gceSTATUS status; + gctBOOL commitEntered = gcvFALSE; + gctBOOL contextAcquired = gcvFALSE; + gckHARDWARE hardware; + gctBOOL needCopy = gcvFALSE; + gcsQUEUE_PTR eventRecord = gcvNULL; + gcsQUEUE _eventRecord; + gcsQUEUE_PTR nextEventRecord; + gctBOOL commandBufferMapped = gcvFALSE; + gcoCMDBUF commandBufferObject = gcvNULL; + +#if !gcdNULL_DRIVER + gcsCONTEXT_PTR contextBuffer; + struct _gcoCMDBUF _commandBufferObject; + gctPHYS_ADDR commandBufferPhysical; + gctUINT8_PTR commandBufferLogical; + gctUINT8_PTR commandBufferLink; + gctUINT commandBufferSize; + gctSIZE_T nopBytes; + gctSIZE_T pipeBytes; + gctSIZE_T linkBytes; + gctSIZE_T bytes; + gctUINT32 offset; +#if gcdNONPAGED_MEMORY_CACHEABLE + gctPHYS_ADDR entryPhysical; +#endif + gctPOINTER entryLogical; + gctSIZE_T entryBytes; +#if gcdNONPAGED_MEMORY_CACHEABLE + gctPHYS_ADDR exitPhysical; +#endif + gctPOINTER exitLogical; + gctSIZE_T exitBytes; + gctPHYS_ADDR waitLinkPhysical; + gctPOINTER waitLinkLogical; + gctSIZE_T waitLinkBytes; + gctPHYS_ADDR waitPhysical; + gctPOINTER waitLogical; + gctUINT32 waitOffset; + gctSIZE_T waitSize; + +#if gcdDUMP_COMMAND + gctPOINTER contextDumpLogical = gcvNULL; + gctSIZE_T contextDumpBytes = 0; + gctPOINTER bufferDumpLogical = gcvNULL; + gctSIZE_T bufferDumpBytes = 0; +# endif +#endif + + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG( + "Command=0x%x CommandBuffer=0x%x ProcessID=%d", + Command, CommandBuffer, ProcessID + ); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + if (Command->kernel->core == gcvCORE_2D) + { + /* There is no context for 2D. */ + Context = gcvNULL; + } + + gcmkONERROR(_FlushMMU(Command)); + + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(Command, gcvFALSE)); + commitEntered = gcvTRUE; + + /* Acquire the context switching mutex. */ + gcmkONERROR(gckOS_AcquireMutex( + Command->os, Command->mutexContext, gcvINFINITE + )); + contextAcquired = gcvTRUE; + + /* Extract the gckHARDWARE and gckEVENT objects. */ + hardware = Command->kernel->hardware; + + /* Check wehther we need to copy the structures or not. */ + gcmkONERROR(gckOS_QueryNeedCopy(Command->os, ProcessID, &needCopy)); + +#if gcdNULL_DRIVER + /* Context switch required? */ + if ((Context != gcvNULL) && (Command->currContext != Context)) + { + /* Yes, merge in the deltas. */ + gckCONTEXT_Update(Context, ProcessID, StateDelta); + + /* Update the current context. */ + Command->currContext = Context; + } +#else + if (needCopy) + { + commandBufferObject = &_commandBufferObject; + + gcmkONERROR(gckOS_CopyFromUserData( + Command->os, + commandBufferObject, + CommandBuffer, + gcmSIZEOF(struct _gcoCMDBUF) + )); + + gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER); + } + else + { + gcmkONERROR(gckOS_MapUserPointer( + Command->os, + CommandBuffer, + gcmSIZEOF(struct _gcoCMDBUF), + &pointer + )); + + commandBufferObject = pointer; + + gcmkVERIFY_OBJECT(commandBufferObject, gcvOBJ_COMMANDBUFFER); + commandBufferMapped = gcvTRUE; + } + + /* Query the size of NOP command. */ + gcmkONERROR(gckHARDWARE_Nop( + hardware, gcvNULL, &nopBytes + )); + + /* Query the size of pipe select command sequence. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + hardware, gcvNULL, gcvPIPE_3D, &pipeBytes + )); + + /* Query the size of LINK command. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, gcvNULL, gcvNULL, 0, &linkBytes + )); + + /* Compute the command buffer entry and the size. */ + commandBufferLogical + = (gctUINT8_PTR) commandBufferObject->logical + + commandBufferObject->startOffset; + + gcmkONERROR(gckOS_GetPhysicalAddress( + Command->os, + commandBufferLogical, + (gctUINT32_PTR)&commandBufferPhysical + )); + + commandBufferSize + = commandBufferObject->offset + + Command->reservedTail + - commandBufferObject->startOffset; + + /* Context switch required? */ + if (Context == gcvNULL) + { + /* See if we have to switch pipes for the command buffer. */ + if (commandBufferObject->entryPipe == Command->pipeSelect) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the entry command buffer pipes + ** are different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Compute the entry. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset; +#endif + entryLogical = commandBufferLogical + offset; + entryBytes = commandBufferSize - offset; + } + else if (Command->currContext != Context) + { + /* Temporary disable context length oprimization. */ + Context->dirty = gcvTRUE; + + /* Get the current context buffer. */ + contextBuffer = Context->buffer; + + /* Yes, merge in the deltas. */ + gcmkONERROR(gckCONTEXT_Update(Context, ProcessID, StateDelta)); + + /* Determine context entry and exit points. */ + if (0) + { + /* Reset 2D dirty flag. */ + Context->dirty2D = gcvFALSE; + + if (Context->dirty || commandBufferObject->using3D) + { + /*************************************************************** + ** SWITCHING CONTEXT: 2D and 3D are used. + */ + + /* Reset 3D dirty flag. */ + Context->dirty3D = gcvFALSE; + + /* Compute the entry. */ + if (Command->pipeSelect == gcvPIPE_2D) + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; + entryBytes = Context->bufferSize - pipeBytes; + } + else + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical; + entryBytes = Context->bufferSize; + } + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_3D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Ensure the NOP between 2D and 3D is in place so that the + execution falls through from 2D to 3D. */ + gcmkONERROR(gckHARDWARE_Nop( + hardware, + contextBuffer->link2D, + &nopBytes + )); + + /* Generate a LINK from the context buffer to + the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link3D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + + /* Mark context as not dirty. */ + Context->dirty = gcvFALSE; + } + else + { + /*************************************************************** + ** SWITCHING CONTEXT: 2D only command buffer. + */ + + /* Mark 3D as dirty. */ + Context->dirty3D = gcvTRUE; + + /* Compute the entry. */ + if (Command->pipeSelect == gcvPIPE_2D) + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; + entryBytes = Context->entryOffset3D - pipeBytes; + } + else + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical; + entryBytes = Context->entryOffset3D; + } + + /* Store the current context buffer. */ + Context->dirtyBuffer = contextBuffer; + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_2D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* 3D is not used, generate a LINK from the end of 2D part of + the context buffer to the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link2D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + } + + /* Not using 2D. */ + else + { + /* Mark 2D as dirty. */ + Context->dirty2D = gcvTRUE; + + /* Store the current context buffer. */ + Context->dirtyBuffer = contextBuffer; + + if (Context->dirty || commandBufferObject->using3D) + { + /*************************************************************** + ** SWITCHING CONTEXT: 3D only command buffer. + */ + + /* Reset 3D dirty flag. */ + Context->dirty3D = gcvFALSE; + + /* Determine context buffer entry offset. */ + offset = (Command->pipeSelect == gcvPIPE_3D) + + /* Skip pipe switching sequence. */ + ? Context->entryOffset3D + pipeBytes + + /* Do not skip pipe switching sequence. */ + : Context->entryOffset3D; + + /* Compute the entry. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + offset; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + offset; + entryBytes = Context->bufferSize - offset; + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_3D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Generate a LINK from the context buffer to + the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link3D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + else + { + /*************************************************************** + ** SWITCHING CONTEXT: "XD" command buffer - neither 2D nor 3D. + */ + + /* Mark 3D as dirty. */ + Context->dirty3D = gcvTRUE; + + /* Compute the entry. */ + if (Command->pipeSelect == gcvPIPE_3D) + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical + = (gctUINT8_PTR) contextBuffer->physical + + Context->entryOffsetXDFrom3D; +#endif + entryLogical + = (gctUINT8_PTR) contextBuffer->logical + + Context->entryOffsetXDFrom3D; + + entryBytes + = Context->bufferSize + - Context->entryOffsetXDFrom3D; + } + else + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical + = (gctUINT8_PTR) contextBuffer->physical + + Context->entryOffsetXDFrom2D; +#endif + entryLogical + = (gctUINT8_PTR) contextBuffer->logical + + Context->entryOffsetXDFrom2D; + + entryBytes + = Context->totalSize + - Context->entryOffsetXDFrom2D; + } + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_3D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Generate a LINK from the context buffer to + the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link3D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + } + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the context buffer cache. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + entryPhysical, + entryLogical, + entryBytes + )); +#endif + + /* Update the current context. */ + Command->currContext = Context; + +#if gcdDUMP_COMMAND + contextDumpLogical = entryLogical; + contextDumpBytes = entryBytes; +#endif + } + + /* Same context. */ + else + { + /* Determine context entry and exit points. */ + if (commandBufferObject->using2D && Context->dirty2D) + { + /* Reset 2D dirty flag. */ + Context->dirty2D = gcvFALSE; + + /* Get the "dirty" context buffer. */ + contextBuffer = Context->dirtyBuffer; + + if (commandBufferObject->using3D && Context->dirty3D) + { + /* Reset 3D dirty flag. */ + Context->dirty3D = gcvFALSE; + + /* Compute the entry. */ + if (Command->pipeSelect == gcvPIPE_2D) + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; + entryBytes = Context->bufferSize - pipeBytes; + } + else + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical; + entryBytes = Context->bufferSize; + } + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_3D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Ensure the NOP between 2D and 3D is in place so that the + execution falls through from 2D to 3D. */ + gcmkONERROR(gckHARDWARE_Nop( + hardware, + contextBuffer->link2D, + &nopBytes + )); + + /* Generate a LINK from the context buffer to + the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link3D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + else + { + /* Compute the entry. */ + if (Command->pipeSelect == gcvPIPE_2D) + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + pipeBytes; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + pipeBytes; + entryBytes = Context->entryOffset3D - pipeBytes; + } + else + { +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical; + entryBytes = Context->entryOffset3D; + } + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_2D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* 3D is not used, generate a LINK from the end of 2D part of + the context buffer to the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link2D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + } + else + { + if (commandBufferObject->using3D && Context->dirty3D) + { + /* Reset 3D dirty flag. */ + Context->dirty3D = gcvFALSE; + + /* Get the "dirty" context buffer. */ + contextBuffer = Context->dirtyBuffer; + + /* Determine context buffer entry offset. */ + offset = (Command->pipeSelect == gcvPIPE_3D) + + /* Skip pipe switching sequence. */ + ? Context->entryOffset3D + pipeBytes + + /* Do not skip pipe switching sequence. */ + : Context->entryOffset3D; + + /* Compute the entry. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) contextBuffer->physical + offset; +#endif + entryLogical = (gctUINT8_PTR) contextBuffer->logical + offset; + entryBytes = Context->bufferSize - offset; + + /* See if we have to switch pipes between the context + and command buffers. */ + if (commandBufferObject->entryPipe == gcvPIPE_3D) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the initial context pipes are + different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Generate a LINK from the context buffer to + the command buffer. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + contextBuffer->link3D, + commandBufferLogical + offset, + commandBufferSize - offset, + &linkBytes + )); + } + else + { + /* See if we have to switch pipes for the command buffer. */ + if (commandBufferObject->entryPipe == Command->pipeSelect) + { + /* Skip pipe switching sequence. */ + offset = pipeBytes; + } + else + { + /* The current hardware and the entry command buffer pipes + ** are different, switch to the correct pipe. */ + gcmkONERROR(gckHARDWARE_PipeSelect( + Command->kernel->hardware, + commandBufferLogical, + commandBufferObject->entryPipe, + &pipeBytes + )); + + /* Do not skip pipe switching sequence. */ + offset = 0; + } + + /* Compute the entry. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + entryPhysical = (gctUINT8_PTR) commandBufferPhysical + offset; +#endif + entryLogical = commandBufferLogical + offset; + entryBytes = commandBufferSize - offset; + } + } + } + +#if gcdDUMP_COMMAND + bufferDumpLogical = commandBufferLogical + offset; + bufferDumpBytes = commandBufferSize - offset; +#endif + +#if gcdSECURE_USER + /* Process user hints. */ + gcmkONERROR(_ProcessHints(Command, ProcessID, commandBufferObject)); +#endif + + /* Get the current offset. */ + offset = Command->offset; + + /* Compute number of bytes left in current kernel command queue. */ + bytes = Command->pageSize - offset; + + /* Query the size of WAIT/LINK command sequence. */ + gcmkONERROR(gckHARDWARE_WaitLink( + hardware, + gcvNULL, + offset, + &waitLinkBytes, + gcvNULL, + gcvNULL + )); + + /* Is there enough space in the current command queue? */ + if (bytes < waitLinkBytes) + { + /* No, create a new one. */ + gcmkONERROR(_NewQueue(Command)); + + /* Get the new current offset. */ + offset = Command->offset; + + /* Recompute the number of bytes in the new kernel command queue. */ + bytes = Command->pageSize - offset; + gcmkASSERT(bytes >= waitLinkBytes); + } + + /* Compute the location if WAIT/LINK command sequence. */ + waitLinkPhysical = (gctUINT8_PTR) Command->physical + offset; + waitLinkLogical = (gctUINT8_PTR) Command->logical + offset; + + /* Determine the location to jump to for the command buffer being + ** scheduled. */ + if (Command->newQueue) + { + /* New command queue, jump to the beginning of it. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + exitPhysical = Command->physical; +#endif + exitLogical = Command->logical; + exitBytes = Command->offset + waitLinkBytes; + } + else + { + /* Still within the preexisting command queue, jump to the new + WAIT/LINK command sequence. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + exitPhysical = waitLinkPhysical; +#endif + exitLogical = waitLinkLogical; + exitBytes = waitLinkBytes; + } + + /* Add a new WAIT/LINK command sequence. When the command buffer which is + currently being scheduled is fully executed by the GPU, the FE will + jump to this WAIT/LINK sequence. */ + gcmkONERROR(gckHARDWARE_WaitLink( + hardware, + waitLinkLogical, + offset, + &waitLinkBytes, + &waitOffset, + &waitSize + )); + + /* Compute the location if WAIT command. */ + waitPhysical = (gctUINT8_PTR) waitLinkPhysical + waitOffset; + waitLogical = (gctUINT8_PTR) waitLinkLogical + waitOffset; + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the command queue cache. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + exitPhysical, + exitLogical, + exitBytes + )); +#endif + + /* Determine the location of the LINK command in the command buffer. */ + commandBufferLink + = (gctUINT8_PTR) commandBufferObject->logical + + commandBufferObject->offset; + + /* Generate a LINK from the end of the command buffer being scheduled + back to the kernel command queue. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + commandBufferLink, + exitLogical, + exitBytes, + &linkBytes + )); + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the command buffer cache. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + ProcessID, + gcvNULL, + commandBufferPhysical, + commandBufferLogical, + commandBufferSize + )); +#endif + + /* Generate a LINK from the previous WAIT/LINK command sequence to the + entry determined above (either the context or the command buffer). + This LINK replaces the WAIT instruction from the previous WAIT/LINK + pair, therefore we use WAIT metrics for generation of this LINK. + This action will execute the entire sequence. */ + gcmkONERROR(gckHARDWARE_Link( + hardware, + Command->waitLogical, + entryLogical, + entryBytes, + &Command->waitSize + )); + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache for the link. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + Command->waitPhysical, + Command->waitLogical, + Command->waitSize + )); +#endif + + gcmkDUMPCOMMAND( + Command->os, + Command->waitLogical, + Command->waitSize, + gceDUMP_BUFFER_LINK, + gcvFALSE + ); + + gcmkDUMPCOMMAND( + Command->os, + contextDumpLogical, + contextDumpBytes, + gceDUMP_BUFFER_CONTEXT, + gcvFALSE + ); + + gcmkDUMPCOMMAND( + Command->os, + bufferDumpLogical, + bufferDumpBytes, + gceDUMP_BUFFER_USER, + gcvFALSE + ); + + gcmkDUMPCOMMAND( + Command->os, + waitLinkLogical, + waitLinkBytes, + gceDUMP_BUFFER_WAITLINK, + gcvFALSE + ); + + /* Update the current pipe. */ + Command->pipeSelect = commandBufferObject->exitPipe; + + /* Update command queue offset. */ + Command->offset += waitLinkBytes; + Command->newQueue = gcvFALSE; + + /* Update address of last WAIT. */ + Command->waitPhysical = waitPhysical; + Command->waitLogical = waitLogical; + Command->waitSize = waitSize; + + /* Update queue tail pointer. */ + gcmkONERROR(gckHARDWARE_UpdateQueueTail( + hardware, Command->logical, Command->offset + )); + +#if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP + gcmkPRINT("@[kernel.commit]"); +#endif +#endif /* gcdNULL_DRIVER */ + + /* Release the context switching mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + contextAcquired = gcvFALSE; + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(Command, gcvFALSE)); + commitEntered = gcvFALSE; + + /* Loop while there are records in the queue. */ + while (EventQueue != gcvNULL) + { + if (needCopy) + { + /* Point to stack record. */ + eventRecord = &_eventRecord; + + /* Copy the data from the client. */ + gcmkONERROR(gckOS_CopyFromUserData( + Command->os, eventRecord, EventQueue, gcmSIZEOF(gcsQUEUE) + )); + } + else + { + /* Map record into kernel memory. */ + gcmkONERROR(gckOS_MapUserPointer(Command->os, + EventQueue, + gcmSIZEOF(gcsQUEUE), + &pointer)); + + eventRecord = pointer; + } + + /* Append event record to event queue. */ + gcmkONERROR(gckEVENT_AddList( + Command->kernel->eventObj, &eventRecord->iface, gcvKERNEL_PIXEL, gcvTRUE + )); + + /* Next record in the queue. */ + nextEventRecord = eventRecord->next; + + if (!needCopy) + { + /* Unmap record from kernel memory. */ + gcmkONERROR(gckOS_UnmapUserPointer( + Command->os, EventQueue, gcmSIZEOF(gcsQUEUE), (gctPOINTER *) eventRecord + )); + + eventRecord = gcvNULL; + } + + EventQueue = nextEventRecord; + } + + if (Command->kernel->eventObj->queueHead == gcvNULL) + { + /* Commit done event by which work thread knows all jobs done. */ + gcmkVERIFY_OK( + gckEVENT_CommitDone(Command->kernel->eventObj, gcvKERNEL_PIXEL)); + } + + /* Submit events. */ + gcmkONERROR(gckEVENT_Submit(Command->kernel->eventObj, gcvTRUE, gcvFALSE)); + + /* Unmap the command buffer pointer. */ + if (commandBufferMapped) + { + gcmkONERROR(gckOS_UnmapUserPointer( + Command->os, + CommandBuffer, + gcmSIZEOF(struct _gcoCMDBUF), + commandBufferObject + )); + + commandBufferMapped = gcvFALSE; + } + + /* Return status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if ((eventRecord != gcvNULL) && !needCopy) + { + /* Roll back. */ + gcmkVERIFY_OK(gckOS_UnmapUserPointer( + Command->os, + EventQueue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) eventRecord + )); + } + + if (contextAcquired) + { + /* Release the context switching mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + } + + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(Command, gcvFALSE)); + } + + /* Unmap the command buffer pointer. */ + if (commandBufferMapped) + { + gcmkVERIFY_OK(gckOS_UnmapUserPointer( + Command->os, + CommandBuffer, + gcmSIZEOF(struct _gcoCMDBUF), + commandBufferObject + )); + } + + /* Return status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Reserve +** +** Reserve space in the command queue. Also acquire the command queue mutex. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gctSIZE_T RequestedBytes +** Number of bytes previously reserved. +** +** OUTPUT: +** +** gctPOINTER * Buffer +** Pointer to a variable that will receive the address of the reserved +** space. +** +** gctSIZE_T * BufferSize +** Pointer to a variable that will receive the number of bytes +** available in the command queue. +*/ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ) +{ + gceSTATUS status; + gctSIZE_T bytes; + gctSIZE_T requiredBytes; + gctUINT32 requestedAligned; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Compute aligned number of reuested bytes. */ + requestedAligned = gcmALIGN(RequestedBytes, Command->alignment); + + /* Another WAIT/LINK command sequence will have to be appended after + the requested area being reserved. Compute the number of bytes + required for WAIT/LINK at the location after the reserved area. */ + gcmkONERROR(gckHARDWARE_WaitLink( + Command->kernel->hardware, + gcvNULL, + Command->offset + requestedAligned, + &requiredBytes, + gcvNULL, + gcvNULL + )); + + /* Compute total number of bytes required. */ + requiredBytes += requestedAligned; + + /* Compute number of bytes available in command queue. */ + bytes = Command->pageSize - Command->offset; + + /* Is there enough space in the current command queue? */ + if (bytes < requiredBytes) + { + /* Create a new command queue. */ + gcmkONERROR(_NewQueue(Command)); + + /* Recompute the number of bytes in the new kernel command queue. */ + bytes = Command->pageSize - Command->offset; + + /* Still not enough space? */ + if (bytes < requiredBytes) + { + /* Rare case, not enough room in command queue. */ + gcmkONERROR(gcvSTATUS_BUFFER_TOO_SMALL); + } + } + + /* Return pointer to empty slot command queue. */ + *Buffer = (gctUINT8 *) Command->logical + Command->offset; + + /* Return number of bytes left in command queue. */ + *BufferSize = bytes; + + /* Success. */ + gcmkFOOTER_ARG("*Buffer=0x%x *BufferSize=%lu", *Buffer, *BufferSize); + return gcvSTATUS_OK; + +OnError: + /* Return 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 + ) +{ + gceSTATUS status; + + gctPHYS_ADDR waitLinkPhysical; + gctUINT8_PTR waitLinkLogical; + gctUINT32 waitLinkOffset; + gctSIZE_T waitLinkBytes; + + gctPHYS_ADDR waitPhysical; + gctPOINTER waitLogical; + gctUINT32 waitOffset; + gctSIZE_T waitBytes; + +#if gcdNONPAGED_MEMORY_CACHEABLE + gctPHYS_ADDR execPhysical; +#endif + gctPOINTER execLogical; + gctSIZE_T execBytes; + + gcmkHEADER_ARG("Command=0x%x RequestedBytes=%lu", Command, RequestedBytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Compute offset for WAIT/LINK. */ + waitLinkOffset = Command->offset + RequestedBytes; + + /* Compute number of bytes left in command queue. */ + waitLinkBytes = Command->pageSize - waitLinkOffset; + + /* Compute the location if WAIT/LINK command sequence. */ + waitLinkPhysical = (gctUINT8_PTR) Command->physical + waitLinkOffset; + waitLinkLogical = (gctUINT8_PTR) Command->logical + waitLinkOffset; + + /* Append WAIT/LINK in command queue. */ + gcmkONERROR(gckHARDWARE_WaitLink( + Command->kernel->hardware, + waitLinkLogical, + waitLinkOffset, + &waitLinkBytes, + &waitOffset, + &waitBytes + )); + + /* Compute the location if WAIT command. */ + waitPhysical = (gctUINT8_PTR) waitLinkPhysical + waitOffset; + waitLogical = waitLinkLogical + waitOffset; + + /* Determine the location to jump to for the command buffer being + ** scheduled. */ + if (Command->newQueue) + { + /* New command queue, jump to the beginning of it. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + execPhysical = Command->physical; +#endif + execLogical = Command->logical; + execBytes = waitLinkOffset + waitLinkBytes; + } + else + { + /* Still within the preexisting command queue, jump directly to the + reserved area. */ +#if gcdNONPAGED_MEMORY_CACHEABLE + execPhysical = (gctUINT8 *) Command->physical + Command->offset; +#endif + execLogical = (gctUINT8 *) Command->logical + Command->offset; + execBytes = RequestedBytes + waitLinkBytes; + } + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + execPhysical, + execLogical, + execBytes + )); +#endif + + /* Convert the last WAIT into a LINK. */ + gcmkONERROR(gckHARDWARE_Link( + Command->kernel->hardware, + Command->waitLogical, + execLogical, + execBytes, + &Command->waitSize + )); + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache. */ + gcmkONERROR(gckOS_CacheClean( + Command->os, + Command->kernelProcessID, + gcvNULL, + Command->waitPhysical, + Command->waitLogical, + Command->waitSize + )); +#endif + + gcmkDUMPCOMMAND( + Command->os, + Command->waitLogical, + Command->waitSize, + gceDUMP_BUFFER_LINK, + gcvFALSE + ); + + gcmkDUMPCOMMAND( + Command->os, + execLogical, + execBytes, + gceDUMP_BUFFER_KERNEL, + gcvFALSE + ); + + /* Update the pointer to the last WAIT. */ + Command->waitPhysical = waitPhysical; + Command->waitLogical = waitLogical; + Command->waitSize = waitBytes; + + /* Update the command queue. */ + Command->offset += RequestedBytes + waitLinkBytes; + Command->newQueue = gcvFALSE; + + /* Update queue tail pointer. */ + gcmkONERROR(gckHARDWARE_UpdateQueueTail( + Command->kernel->hardware, Command->logical, Command->offset + )); + +#if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP + gcmkPRINT("@[kernel.execute]"); +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Stall +** +** The calling thread will be suspended until the command queue has been +** completed. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to an gckCOMMAND object. +** +** gctBOOL FromPower +** Determines whether the call originates from inside the power +** management or not. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Stall( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ) +{ +#if gcdNULL_DRIVER + /* Do nothing with infinite hardware. */ + return gcvSTATUS_OK; +#else + gckOS os; + gckHARDWARE hardware; + gckEVENT eventObject; + gceSTATUS status; + gctSIGNAL signal = gcvNULL; + gctUINT timer = 0; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* 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. */ + eventObject = Command->kernel->eventObj; + gcmkVERIFY_OBJECT(eventObject, gcvOBJ_EVENT); + + /* Allocate the signal. */ + gcmkONERROR(gckOS_CreateSignal(os, gcvTRUE, &signal)); + + /* Append the EVENT command to trigger the signal. */ + gcmkONERROR(gckEVENT_Signal(eventObject, signal, gcvKERNEL_PIXEL)); + + /* Submit the event queue. */ + gcmkONERROR(gckEVENT_Submit(eventObject, gcvTRUE, FromPower)); + +#if gcdDUMP_COMMAND && !gcdSIMPLE_COMMAND_DUMP + gcmkPRINT("@[kernel.stall]"); +#endif + + if (status == gcvSTATUS_CHIP_NOT_READY) + { + /* Error. */ + goto OnError; + } + + do + { + /* Wait for the signal. */ + status = gckOS_WaitSignal(os, signal, gcdGPU_ADVANCETIMER); + + if (status == gcvSTATUS_TIMEOUT) + { +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gctUINT32 idle; + + /* Read idle register. */ + gcmkVERIFY_OK(gckHARDWARE_GetIdle( + hardware, gcvFALSE, &idle + )); + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): idle=%08x", + __FUNCTION__, __LINE__, idle + ); + + gcmkONERROR(gckOS_MemoryBarrier(os, gcvNULL)); + +#ifdef __QNXNTO__ + gctUINT32 reg_cmdbuf_fetch; + gctUINT32 reg_intr; + + gcmkVERIFY_OK(gckOS_ReadRegisterEx( + Command->kernel->hardware->os, Command->kernel->core, 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_ReadRegisterEx( + Command->kernel->hardware->os, Command->kernel->core, 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 +#endif + /* Advance timer. */ + timer += gcdGPU_ADVANCETIMER; + } + else if (status == gcvSTATUS_INTERRUPTED) + { + gcmkONERROR(gcvSTATUS_INTERRUPTED); + } + + } + while (gcmIS_ERROR(status) +#if gcdGPU_TIMEOUT + && (timer < Command->kernel->timeOut) +#endif + ); + + /* Bail out on timeout. */ + if (gcmIS_ERROR(status)) + { + /* Broadcast the stuck GPU. */ + gcmkONERROR(gckOS_Broadcast( + os, hardware, gcvBROADCAST_GPU_STUCK + )); + + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } + + /* Delete the signal. */ + gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (signal != gcvNULL) + { + /* Free the signal. */ + gcmkVERIFY_OK(gckOS_DestroySignal(os, signal)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +#endif +} + +/******************************************************************************* +** +** gckCOMMAND_Attach +** +** Attach user process. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to a gckCOMMAND object. +** +** gctUINT32 ProcessID +** Current process ID. +** +** OUTPUT: +** +** gckCONTEXT * Context +** Pointer to a variable that will receive a pointer to a new +** gckCONTEXT object. +** +** gctSIZE_T * StateCount +** Pointer to a variable that will receive the number of states +** in the context buffer. +*/ +gceSTATUS +gckCOMMAND_Attach( + IN gckCOMMAND Command, + OUT gckCONTEXT * Context, + OUT gctSIZE_T * StateCount, + IN gctUINT32 ProcessID + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Acquire the context switching mutex. */ + gcmkONERROR(gckOS_AcquireMutex( + Command->os, Command->mutexContext, gcvINFINITE + )); + acquired = gcvTRUE; + + /* Construct a gckCONTEXT object. */ + gcmkONERROR(gckCONTEXT_Construct( + Command->os, + Command->kernel->hardware, + ProcessID, + Context + )); + + /* Return the number of states in the context. */ + * StateCount = (* Context)->stateCount; + + /* Release the context switching mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + acquired = gcvFALSE; + + /* Success. */ + gcmkFOOTER_ARG("*Context=0x%x", *Context); + return gcvSTATUS_OK; + +OnError: + /* Release mutex. */ + if (acquired) + { + /* Release the context switching mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + acquired = gcvFALSE; + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckCOMMAND_Detach +** +** Detach user process. +** +** INPUT: +** +** gckCOMMAND Command +** Pointer to a gckCOMMAND object. +** +** gckCONTEXT Context +** Pointer to a gckCONTEXT object to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckCOMMAND_Detach( + IN gckCOMMAND Command, + IN gckCONTEXT Context + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Command=0x%x Context=0x%x", Command, Context); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + /* Acquire the context switching mutex. */ + gcmkONERROR(gckOS_AcquireMutex( + Command->os, Command->mutexContext, gcvINFINITE + )); + acquired = gcvTRUE; + + /* Construct a gckCONTEXT object. */ + gcmkONERROR(gckCONTEXT_Destroy(Context)); + + /* Release the context switching mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + acquired = gcvFALSE; + + /* Return the status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + /* Release mutex. */ + if (acquired) + { + /* Release the context switching mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Command->os, Command->mutexContext)); + acquired = gcvFALSE; + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command_vg.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command_vg.c new file mode 100644 index 0000000..60f5089 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_command_vg.c @@ -0,0 +1,3648 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#if gcdENABLE_VG + +#include "gc_hal_kernel_hardware_command_vg.h" + +#define _GC_OBJ_ZONE gcvZONE_COMMAND + +/******************************************************************************\ +*********************************** Debugging ********************************** +\******************************************************************************/ + +#define gcvDISABLE_TIMEOUT 1 +#define gcvDUMP_COMMAND_BUFFER 0 +#define gcvDUMP_COMMAND_LINES 0 + + +#if gcvDEBUG || defined(EMULATOR) || gcvDISABLE_TIMEOUT +# define gcvQUEUE_TIMEOUT ~0 +#else +# define gcvQUEUE_TIMEOUT 10 +#endif + + +/******************************************************************************\ +********************************** Definitions ********************************* +\******************************************************************************/ + +/* Minimum buffer size. */ +#define gcvMINUMUM_BUFFER \ + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + \ + gcmSIZEOF(gcsKERNEL_CMDQUEUE) * 2 + +#define gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \ + static gceSTATUS \ + _EventHandler_##Block##_##Number( \ + IN gckVGKERNEL Kernel \ + ) + +#define gcmDEFINE_INTERRUPT_HANDLER(Block, Number) \ + gcmDECLARE_INTERRUPT_HANDLER(Block, Number) \ + { \ + return _EventHandler_Block( \ + Kernel, \ + &Kernel->command->taskTable[gcvBLOCK_##Block], \ + gcvFALSE \ + ); \ + } + +#define gcmDEFINE_INTERRUPT_HANDLER_ENTRY(Block, Number) \ + { gcvBLOCK_##Block, _EventHandler_##Block##_##Number } + +/* Block interrupt handling table entry. */ +typedef struct _gcsBLOCK_INTERRUPT_HANDLER * gcsBLOCK_INTERRUPT_HANDLER_PTR; +typedef struct _gcsBLOCK_INTERRUPT_HANDLER +{ + gceBLOCK block; + gctINTERRUPT_HANDLER handler; +} +gcsBLOCK_INTERRUPT_HANDLER; + +/* Queue control functions. */ +typedef struct _gcsQUEUE_UPDATE_CONTROL * gcsQUEUE_UPDATE_CONTROL_PTR; +typedef struct _gcsQUEUE_UPDATE_CONTROL +{ + gctOBJECT_HANDLER execute; + gctOBJECT_HANDLER update; + gctOBJECT_HANDLER lastExecute; + gctOBJECT_HANDLER lastUpdate; +} +gcsQUEUE_UPDATE_CONTROL; + + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +static gceSTATUS +_WaitForIdle( + IN gckVGCOMMAND Command, + IN gcsKERNEL_QUEUE_HEADER_PTR Queue + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctUINT32 idle; + gctUINT timeout = 0; + + /* Loop while not idle. */ + while (Queue->pending) + { + /* Did we reach the timeout limit? */ + if (timeout == gcvQUEUE_TIMEOUT) + { + /* Hardware is probably dead... */ + return gcvSTATUS_TIMEOUT; + } + + /* Sleep for 100ms. */ + gcmkERR_BREAK(gckOS_Delay(Command->os, 100)); + + /* Not the first loop? */ + if (timeout > 0) + { + /* Read IDLE register. */ + gcmkVERIFY_OK(gckVGHARDWARE_GetIdle(Command->hardware, &idle)); + + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_COMMAND, + "%s: timeout, IDLE=%08X\n", + __FUNCTION__, idle + ); + } + + /* Increment the timeout counter. */ + timeout += 1; + } + + /* Return status. */ + return status; +} + +static gctINT32 +_GetNextInterrupt( + IN gckVGCOMMAND Command, + IN gceBLOCK Block + ) +{ + gctUINT index; + gcsBLOCK_TASK_ENTRY_PTR entry; + gctINT32 interrupt; + + /* Get the block entry. */ + entry = &Command->taskTable[Block]; + + /* Make sure we have initialized interrupts. */ + gcmkASSERT(entry->interruptCount > 0); + + /* Decrement the interrupt usage semaphore. */ + gcmkVERIFY_OK(gckOS_DecrementSemaphore( + Command->os, entry->interruptSemaphore + )); + + /* Get the value index. */ + index = entry->interruptIndex; + + /* Get the interrupt value. */ + interrupt = entry->interruptArray[index]; + + /* Must be a valid value. */ + gcmkASSERT((interrupt >= 0) && (interrupt <= 31)); + + /* Advance the index to the next value. */ + index += 1; + + /* Set the new index. */ + entry->interruptIndex = (index == entry->interruptCount) + ? 0 + : index; + + /* Return interrupt value. */ + return interrupt; +} + + +/******************************************************************************\ +***************************** Task Storage Management ************************** +\******************************************************************************/ + +/* Minimum task buffer size. */ +#define gcvMIN_TASK_BUFFER \ +( \ + gcmSIZEOF(gcsTASK_CONTAINER) + 128 \ +) + +/* Free list terminator. */ +#define gcvFREE_TASK_TERMINATOR \ +( \ + (gcsTASK_CONTAINER_PTR) gcmINT2PTR(~0) \ +) + + +/*----------------------------------------------------------------------------*/ +/*------------------- Allocated Task Buffer List Management ------------------*/ + +static void +_InsertTaskBuffer( + IN gcsTASK_CONTAINER_PTR AddAfter, + IN gcsTASK_CONTAINER_PTR Buffer + ) +{ + gcsTASK_CONTAINER_PTR addBefore; + + /* Cannot add before the first buffer. */ + gcmkASSERT(AddAfter != gcvNULL); + + /* Create a shortcut to the next buffer. */ + addBefore = AddAfter->allocNext; + + /* Initialize the links. */ + Buffer->allocPrev = AddAfter; + Buffer->allocNext = addBefore; + + /* Link to the previous buffer. */ + AddAfter->allocNext = Buffer; + + /* Link to the next buffer. */ + if (addBefore != gcvNULL) + { + addBefore->allocPrev = Buffer; + } +} + +static void +_RemoveTaskBuffer( + IN gcsTASK_CONTAINER_PTR Buffer + ) +{ + gcsTASK_CONTAINER_PTR prev; + gcsTASK_CONTAINER_PTR next; + + /* Cannot remove the first buffer. */ + gcmkASSERT(Buffer->allocPrev != gcvNULL); + + /* Create shortcuts to the previous and next buffers. */ + prev = Buffer->allocPrev; + next = Buffer->allocNext; + + /* Tail buffer? */ + if (next == gcvNULL) + { + /* Remove from the list. */ + prev->allocNext = gcvNULL; + } + + /* Buffer from the middle. */ + else + { + prev->allocNext = next; + next->allocPrev = prev; + } +} + + +/*----------------------------------------------------------------------------*/ +/*--------------------- Free Task Buffer List Management ---------------------*/ + +static void +_AppendToFreeList( + IN gckVGCOMMAND Command, + IN gcsTASK_CONTAINER_PTR Buffer + ) +{ + /* Cannot be a part of the free list already. */ + gcmkASSERT(Buffer->freePrev == gcvNULL); + gcmkASSERT(Buffer->freeNext == gcvNULL); + + /* First buffer to add? */ + if (Command->taskFreeHead == gcvNULL) + { + /* Terminate the links. */ + Buffer->freePrev = gcvFREE_TASK_TERMINATOR; + Buffer->freeNext = gcvFREE_TASK_TERMINATOR; + + /* Initialize the list pointer. */ + Command->taskFreeHead = Command->taskFreeTail = Buffer; + } + + /* Not the first, add after the tail. */ + else + { + /* Initialize the new tail buffer. */ + Buffer->freePrev = Command->taskFreeTail; + Buffer->freeNext = gcvFREE_TASK_TERMINATOR; + + /* Add after the tail. */ + Command->taskFreeTail->freeNext = Buffer; + Command->taskFreeTail = Buffer; + } +} + +static void +_RemoveFromFreeList( + IN gckVGCOMMAND Command, + IN gcsTASK_CONTAINER_PTR Buffer + ) +{ + /* Has to be a part of the free list. */ + gcmkASSERT(Buffer->freePrev != gcvNULL); + gcmkASSERT(Buffer->freeNext != gcvNULL); + + /* Head buffer? */ + if (Buffer->freePrev == gcvFREE_TASK_TERMINATOR) + { + /* Tail buffer as well? */ + if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR) + { + /* Reset the list pointer. */ + Command->taskFreeHead = Command->taskFreeTail = gcvNULL; + } + + /* No, just the head. */ + else + { + /* Update the head. */ + Command->taskFreeHead = Buffer->freeNext; + + /* Terminate the next buffer. */ + Command->taskFreeHead->freePrev = gcvFREE_TASK_TERMINATOR; + } + } + + /* Not the head. */ + else + { + /* Tail buffer? */ + if (Buffer->freeNext == gcvFREE_TASK_TERMINATOR) + { + /* Update the tail. */ + Command->taskFreeTail = Buffer->freePrev; + + /* Terminate the previous buffer. */ + Command->taskFreeTail->freeNext = gcvFREE_TASK_TERMINATOR; + } + + /* A buffer in the middle. */ + else + { + /* Remove the buffer from the list. */ + Buffer->freePrev->freeNext = Buffer->freeNext; + Buffer->freeNext->freePrev = Buffer->freePrev; + } + } + + /* Reset free list pointers. */ + Buffer->freePrev = gcvNULL; + Buffer->freeNext = gcvNULL; +} + + +/*----------------------------------------------------------------------------*/ +/*-------------------------- Task Buffer Allocation --------------------------*/ + +static void +_SplitTaskBuffer( + IN gckVGCOMMAND Command, + IN gcsTASK_CONTAINER_PTR Buffer, + IN gctUINT Size + ) +{ + /* Determine the size of the new buffer. */ + gctINT splitBufferSize = Buffer->size - Size; + gcmkASSERT(splitBufferSize >= 0); + + /* Is the split buffer big enough to become a separate buffer? */ + if (splitBufferSize >= gcvMIN_TASK_BUFFER) + { + /* Place the new path data. */ + gcsTASK_CONTAINER_PTR splitBuffer = (gcsTASK_CONTAINER_PTR) + ( + (gctUINT8_PTR) Buffer + Size + ); + + /* Set the trimmed buffer size. */ + Buffer->size = Size; + + /* Initialize the split buffer. */ + splitBuffer->referenceCount = 0; + splitBuffer->size = splitBufferSize; + splitBuffer->freePrev = gcvNULL; + splitBuffer->freeNext = gcvNULL; + + /* Link in. */ + _InsertTaskBuffer(Buffer, splitBuffer); + _AppendToFreeList(Command, splitBuffer); + } +} + +static gceSTATUS +_AllocateTaskContainer( + IN gckVGCOMMAND Command, + IN gctUINT Size, + OUT gcsTASK_CONTAINER_PTR * Buffer + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Command=0x%x Size=0x%x, Buffer ==0x%x", Command, Size, Buffer); + + /* Verify arguments. */ + gcmkVERIFY_ARGUMENT(Buffer != gcvNULL); + + do + { + gcsTASK_STORAGE_PTR storage; + gcsTASK_CONTAINER_PTR buffer; + + /* Adjust the size. */ + Size += gcmSIZEOF(gcsTASK_CONTAINER); + + /* Adjust the allocation size if not big enough. */ + if (Size > Command->taskStorageUsable) + { + Command->taskStorageGranularity + = gcmALIGN(Size + gcmSIZEOF(gcsTASK_STORAGE), 1024); + + Command->taskStorageUsable + = Command->taskStorageGranularity - gcmSIZEOF(gcsTASK_STORAGE); + } + + /* Is there a free buffer available? */ + else if (Command->taskFreeHead != gcvNULL) + { + /* Set the initial free buffer. */ + gcsTASK_CONTAINER_PTR buffer = Command->taskFreeHead; + + do + { + /* Is the buffer big enough? */ + if (buffer->size >= Size) + { + /* Remove the buffer from the free list. */ + _RemoveFromFreeList(Command, buffer); + + /* Split the buffer. */ + _SplitTaskBuffer(Command, buffer, Size); + + /* Set the result. */ + * Buffer = buffer; + + gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer); + /* Success. */ + return gcvSTATUS_OK; + } + + /* Get the next free buffer. */ + buffer = buffer->freeNext; + } + while (buffer != gcvFREE_TASK_TERMINATOR); + } + + /* Allocate a container. */ + gcmkERR_BREAK(gckOS_Allocate( + Command->os, + Command->taskStorageGranularity, + (gctPOINTER *) &storage + )); + + /* Link in the storage buffer. */ + storage->next = Command->taskStorage; + Command->taskStorage = storage; + + /* Place the task buffer. */ + buffer = (gcsTASK_CONTAINER_PTR) (storage + 1); + + /* Determine the size of the buffer. */ + buffer->size + = Command->taskStorageGranularity + - gcmSIZEOF(gcsTASK_STORAGE); + + /* Initialize the task buffer. */ + buffer->referenceCount = 0; + buffer->allocPrev = gcvNULL; + buffer->allocNext = gcvNULL; + buffer->freePrev = gcvNULL; + buffer->freeNext = gcvNULL; + + /* Split the buffer. */ + _SplitTaskBuffer(Command, buffer, Size); + + /* Set the result. */ + * Buffer = buffer; + + gcmkFOOTER_ARG("*Buffer=0x%x",*Buffer); + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +static void +_FreeTaskContainer( + IN gckVGCOMMAND Command, + IN gcsTASK_CONTAINER_PTR Buffer + ) +{ + gcsTASK_CONTAINER_PTR prev; + gcsTASK_CONTAINER_PTR next; + gcsTASK_CONTAINER_PTR merged; + + gctSIZE_T mergedSize; + + /* Verify arguments. */ + gcmkASSERT(Buffer != gcvNULL); + gcmkASSERT(Buffer->freePrev == gcvNULL); + gcmkASSERT(Buffer->freeNext == gcvNULL); + + /* Get shortcuts to the previous and next path data buffers. */ + prev = Buffer->allocPrev; + next = Buffer->allocNext; + + /* Is the previous path data buffer already free? */ + if (prev && prev->freeNext) + { + /* The previous path data buffer is the one that remains. */ + merged = prev; + + /* Is the next path data buffer already free? */ + if (next && next->freeNext) + { + /* Merge all three path data buffers into the previous. */ + mergedSize = prev->size + Buffer->size + next->size; + + /* Remove the next path data buffer. */ + _RemoveFromFreeList(Command, next); + _RemoveTaskBuffer(next); + } + else + { + /* Merge the current path data buffer into the previous. */ + mergedSize = prev->size + Buffer->size; + } + + /* Delete the current path data buffer. */ + _RemoveTaskBuffer(Buffer); + + /* Set new size. */ + merged->size = mergedSize; + } + else + { + /* The current path data buffer is the one that remains. */ + merged = Buffer; + + /* Is the next buffer already free? */ + if (next && next->freeNext) + { + /* Merge the next into the current. */ + mergedSize = Buffer->size + next->size; + + /* Remove the next buffer. */ + _RemoveFromFreeList(Command, next); + _RemoveTaskBuffer(next); + + /* Set new size. */ + merged->size = mergedSize; + } + + /* Add the current buffer into the free list. */ + _AppendToFreeList(Command, merged); + } +} + + +/******************************************************************************\ +********************************* Task Scheduling ****************************** +\******************************************************************************/ + +static gceSTATUS +_ScheduleTasks( + IN gckVGCOMMAND Command, + IN gcsTASK_MASTER_TABLE_PTR TaskTable, + IN gctUINT8_PTR PreviousEnd + ) +{ + gceSTATUS status; + + do + { + gctINT block; + gcsTASK_CONTAINER_PTR container; + gcsTASK_MASTER_ENTRY_PTR userTaskEntry; + gcsBLOCK_TASK_ENTRY_PTR kernelTaskEntry; + gcsTASK_PTR userTask; + gctUINT8_PTR kernelTask; + gctINT32 interrupt; + gctUINT8_PTR eventCommand; + + /* Nothing to schedule? */ + if (TaskTable->size == 0) + { + status = gcvSTATUS_OK; + break; + } + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + Command->os, + Command->taskMutex, + gcvINFINITE + )); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d)\n", + __FUNCTION__, __LINE__ + ); + + do + { + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " number of tasks scheduled = %d\n" + " size of event data in bytes = %d\n", + TaskTable->count, + TaskTable->size + ); + + /* Allocate task buffer. */ + gcmkERR_BREAK(_AllocateTaskContainer( + Command, + TaskTable->size, + &container + )); + + /* Determine the task data pointer. */ + kernelTask = (gctUINT8_PTR) (container + 1); + + /* Initialize the reference count. */ + container->referenceCount = TaskTable->count; + + /* Process tasks. */ + for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1) + { + /* Get the current user table entry. */ + userTaskEntry = &TaskTable->table[block]; + + /* Are there tasks scheduled? */ + if (userTaskEntry->head == gcvNULL) + { + /* No, skip to the next block. */ + continue; + } + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " processing tasks for block %d\n", + block + ); + + /* Get the current kernel table entry. */ + kernelTaskEntry = &Command->taskTable[block]; + + /* Are there tasks for the current block scheduled? */ + if (kernelTaskEntry->container == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " first task container for the block added\n", + block + ); + + /* Nothing yet, set the container buffer pointer. */ + kernelTaskEntry->container = container; + kernelTaskEntry->task = (gcsTASK_HEADER_PTR) kernelTask; + } + + /* Yes, append to the end. */ + else + { + kernelTaskEntry->link->cotainer = container; + kernelTaskEntry->link->task = (gcsTASK_HEADER_PTR) kernelTask; + } + + /* Set initial task. */ + userTask = userTaskEntry->head; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " copying user tasks over to the kernel\n" + ); + + /* Copy tasks. */ + do + { + gcsTASK_HEADER_PTR taskHeader = (gcsTASK_HEADER_PTR) (userTask + 1); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " task ID = %d, size = %d\n", + ((gcsTASK_HEADER_PTR) (userTask + 1))->id, + userTask->size + ); + +#ifdef __QNXNTO__ + if (taskHeader->id == gcvTASK_SIGNAL) + { + ((gcsTASK_SIGNAL_PTR)taskHeader)->coid = TaskTable->coid; + ((gcsTASK_SIGNAL_PTR)taskHeader)->rcvid = TaskTable->rcvid; + } +#endif /* __QNXNTO__ */ + /* Copy the task data. */ + gcmkVERIFY_OK(gckOS_MemCopy( + kernelTask, taskHeader, userTask->size + )); + + /* Advance to the next task. */ + kernelTask += userTask->size; + userTask = userTask->next; + } + while (userTask != gcvNULL); + + /* Update link pointer in the header. */ + kernelTaskEntry->link = (gcsTASK_LINK_PTR) kernelTask; + + /* Initialize link task. */ + kernelTaskEntry->link->id = gcvTASK_LINK; + kernelTaskEntry->link->cotainer = gcvNULL; + kernelTaskEntry->link->task = gcvNULL; + + /* Advance the task data pointer. */ + kernelTask += gcmSIZEOF(gcsTASK_LINK); + } + } + while (gcvFALSE); + + /* Release the mutex. */ + gcmkERR_BREAK(gckOS_ReleaseMutex( + Command->os, + Command->taskMutex + )); + + /* Assign interrupts to the blocks. */ + eventCommand = PreviousEnd; + + for (block = gcvBLOCK_COUNT - 1; block >= 0; block -= 1) + { + /* Get the current user table entry. */ + userTaskEntry = &TaskTable->table[block]; + + /* Are there tasks scheduled? */ + if (userTaskEntry->head == gcvNULL) + { + /* No, skip to the next block. */ + continue; + } + + /* Get the interrupt number. */ + interrupt = _GetNextInterrupt(Command, block); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): block = %d interrupt = %d\n", + __FUNCTION__, __LINE__, + block, interrupt + ); + + /* Determine the command position. */ + eventCommand -= Command->info.eventCommandSize; + + /* Append an EVENT command. */ + gcmkERR_BREAK(gckVGCOMMAND_EventCommand( + Command, eventCommand, block, interrupt, gcvNULL + )); + } + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +******************************** Memory Management ***************************** +\******************************************************************************/ + +static gceSTATUS +_HardwareToKernel( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + gckVIDMEM memory; + gctUINT32 offset; +#if gcdDYNAMIC_MAP_RESERVED_MEMORY + gctUINT32 nodePhysical; +#endif + status = gcvSTATUS_OK; + /* Assume a non-virtual node and get the pool manager object. */ + memory = Node->VidMem.memory; + +#if gcdDYNAMIC_MAP_RESERVED_MEMORY + nodePhysical = memory->baseAddress + + Node->VidMem.offset + + Node->VidMem.alignment; + + if (Node->VidMem.kernelVirtual == gcvNULL) + { + status = gckOS_MapPhysical(Os, + nodePhysical, + Node->VidMem.bytes, + (gctPOINTER *)&Node->VidMem.kernelVirtual); + + if (gcmkIS_ERROR(status)) + { + return status; + } + } + + offset = Address - nodePhysical; + *KernelPointer = (gctPOINTER)((gctUINT32)Node->VidMem.kernelVirtual + offset); +#else + /* Determine the header offset within the pool it is allocated in. */ + offset = Address - memory->baseAddress; + + /* Translate the offset into the kernel side pointer. */ + status = gckOS_GetKernelLogicalEx( + Os, + gcvCORE_VG, + offset, + KernelPointer + ); +#endif + + /* Return status. */ + return status; +} + +static gceSTATUS +_ConvertUserCommandBufferPointer( + IN gckVGCOMMAND Command, + IN gcsCMDBUFFER_PTR UserCommandBuffer, + OUT gcsCMDBUFFER_PTR * KernelCommandBuffer + ) +{ + gceSTATUS status, last; + gcsCMDBUFFER_PTR mappedUserCommandBuffer = gcvNULL; + + do + { + gctUINT32 headerAddress; + + /* Map the command buffer structure into the kernel space. */ + gcmkERR_BREAK(gckOS_MapUserPointer( + Command->os, + UserCommandBuffer, + gcmSIZEOF(gcsCMDBUFFER), + (gctPOINTER *) &mappedUserCommandBuffer + )); + + /* Determine the address of the header. */ + headerAddress + = mappedUserCommandBuffer->address + - mappedUserCommandBuffer->bufferOffset; + + /* Translate the logical address to the kernel space. */ + gcmkERR_BREAK(_HardwareToKernel( + Command->os, + mappedUserCommandBuffer->node, + headerAddress, + (gctPOINTER *) KernelCommandBuffer + )); + } + while (gcvFALSE); + + /* Unmap the user command buffer. */ + if (mappedUserCommandBuffer != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_UnmapUserPointer( + Command->os, + UserCommandBuffer, + gcmSIZEOF(gcsCMDBUFFER), + mappedUserCommandBuffer + )); + } + + /* Return status. */ + return status; +} + +static gceSTATUS +_AllocateLinear( + IN gckVGCOMMAND Command, + IN gctUINT Size, + IN gctUINT Alignment, + OUT gcuVIDMEM_NODE_PTR * Node, + OUT gctUINT32 * Address, + OUT gctPOINTER * Logical + ) +{ + gceSTATUS status, last; + gcuVIDMEM_NODE_PTR node = gcvNULL; + gctUINT32 address = (gctUINT32)~0; + + do + { + gcePOOL pool; + gctPOINTER logical; + + /* Allocate from the system pool. */ + pool = gcvPOOL_SYSTEM; + + /* Allocate memory. */ + gcmkERR_BREAK(gckKERNEL_AllocateLinearMemory( + Command->kernel->kernel, &pool, + Size, Alignment, + gcvSURF_TYPE_UNKNOWN, + &node + )); + + /* Do not accept virtual pools for now because we don't handle the + kernel pointer translation at the moment. */ + if (pool == gcvPOOL_VIRTUAL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Lock the command buffer. */ + gcmkERR_BREAK(gckVIDMEM_Lock( + Command->kernel->kernel, + node, + gcvFALSE, + &address + )); + + /* Translate the logical address to the kernel space. */ + gcmkERR_BREAK(_HardwareToKernel( + Command->os, + node, + address, + &logical + )); + + /* Set return values. */ + * Node = node; + * Address = address; + * Logical = logical; + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (node != gcvNULL) + { + /* Unlock the command buffer. */ + if (address != ~0) + { + gcmkCHECK_STATUS(gckVIDMEM_Unlock( + Command->kernel->kernel, node, gcvSURF_TYPE_UNKNOWN, gcvNULL + )); + } + + /* Free the command buffer. */ + gcmkCHECK_STATUS(gckVIDMEM_Free( + node + )); + } + + /* Return status. */ + return status; +} + +static gceSTATUS +_FreeLinear( + IN gckVGKERNEL Kernel, + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gceSTATUS status; + + do + { + /* Unlock the linear buffer. */ + gcmkERR_BREAK(gckVIDMEM_Unlock(Kernel->kernel, Node, gcvSURF_TYPE_UNKNOWN, gcvNULL)); + + /* Free the linear buffer. */ + gcmkERR_BREAK(gckVIDMEM_Free(Node)); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +gceSTATUS +_AllocateCommandBuffer( + IN gckVGCOMMAND Command, + IN gctSIZE_T Size, + OUT gcsCMDBUFFER_PTR * CommandBuffer + ) +{ + gceSTATUS status, last; + gcuVIDMEM_NODE_PTR node = gcvNULL; + + do + { + gctUINT alignedHeaderSize; + gctUINT requestedSize; + gctUINT allocationSize; + gctUINT32 address = 0; + gcsCMDBUFFER_PTR commandBuffer; + gctUINT8_PTR endCommand; + + /* Determine the aligned header size. */ + alignedHeaderSize + = gcmALIGN(gcmSIZEOF(gcsCMDBUFFER), Command->info.addressAlignment); + + /* Align the requested size. */ + requestedSize + = gcmALIGN(Size, Command->info.commandAlignment); + + /* Determine the size of the buffer to allocate. */ + allocationSize + = alignedHeaderSize + + requestedSize + + Command->info.staticTailSize; + + /* Allocate the command buffer. */ + gcmkERR_BREAK(_AllocateLinear( + Command, + allocationSize, + Command->info.addressAlignment, + &node, + &address, + (gctPOINTER *) &commandBuffer + )); + + /* Initialize the structure. */ + commandBuffer->completion = gcvVACANT_BUFFER; + commandBuffer->node = node; + commandBuffer->address = address + alignedHeaderSize; + commandBuffer->bufferOffset = alignedHeaderSize; + commandBuffer->size = requestedSize; + commandBuffer->offset = requestedSize; + commandBuffer->nextAllocated = gcvNULL; + commandBuffer->nextSubBuffer = gcvNULL; + + /* Determine the data count. */ + commandBuffer->dataCount + = (requestedSize + Command->info.staticTailSize) + / Command->info.commandAlignment; + + /* Determine the location of the END command. */ + endCommand + = (gctUINT8_PTR) commandBuffer + + alignedHeaderSize + + requestedSize; + + /* Append an END command. */ + gcmkERR_BREAK(gckVGCOMMAND_EndCommand( + Command, + endCommand, + Command->info.feBufferInt, + gcvNULL + )); + + /* Set the return pointer. */ + * CommandBuffer = commandBuffer; + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (node != gcvNULL) + { + /* Free the command buffer. */ + gcmkCHECK_STATUS(_FreeLinear(Command->kernel, node)); + } + + /* Return status. */ + return status; +} + +static gceSTATUS +_FreeCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsCMDBUFFER_PTR CommandBuffer + ) +{ + gceSTATUS status; + + /* Free the buffer. */ + status = _FreeLinear(Kernel, CommandBuffer->node); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +****************************** TS Overflow Handler ***************************** +\******************************************************************************/ + +static gceSTATUS +_EventHandler_TSOverflow( + IN gckVGKERNEL Kernel + ) +{ + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): **** TS OVERFLOW ENCOUNTERED ****\n", + __FUNCTION__, __LINE__ + ); + + return gcvSTATUS_OK; +} + + +/******************************************************************************\ +****************************** Bus Error Handler ******************************* +\******************************************************************************/ + +static gceSTATUS +_EventHandler_BusError( + IN gckVGKERNEL Kernel + ) +{ + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): **** BUS ERROR ENCOUNTERED ****\n", + __FUNCTION__, __LINE__ + ); + + return gcvSTATUS_OK; +} + +#if gcdPOWER_MANAGEMENT +/******************************************************************************\ +****************************** Power Stall Handler ******************************* +\******************************************************************************/ + +static gceSTATUS +_EventHandler_PowerStall( + IN gckVGKERNEL Kernel + ) +{ + /* Signal. */ + return gckOS_Signal( + Kernel->os, + Kernel->command->powerStallSignal, + gcvTRUE); +} +#endif + +/******************************************************************************\ +******************************** Task Routines ********************************* +\******************************************************************************/ + +typedef gceSTATUS (* gctTASKROUTINE) ( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskLink( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskCluster( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskIncrement( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskDecrement( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskSignal( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskLockdown( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskUnlockVideoMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskFreeVideoMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskFreeContiguousMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskUnmapUserMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gceSTATUS +_TaskUnmapMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ); + +static gctTASKROUTINE _taskRoutine[] = +{ + _TaskLink, /* gcvTASK_LINK */ + _TaskCluster, /* gcvTASK_CLUSTER */ + _TaskIncrement, /* gcvTASK_INCREMENT */ + _TaskDecrement, /* gcvTASK_DECREMENT */ + _TaskSignal, /* gcvTASK_SIGNAL */ + _TaskLockdown, /* gcvTASK_LOCKDOWN */ + _TaskUnlockVideoMemory, /* gcvTASK_UNLOCK_VIDEO_MEMORY */ + _TaskFreeVideoMemory, /* gcvTASK_FREE_VIDEO_MEMORY */ + _TaskFreeContiguousMemory, /* gcvTASK_FREE_CONTIGUOUS_MEMORY */ + _TaskUnmapUserMemory, /* gcvTASK_UNMAP_USER_MEMORY */ + _TaskUnmapMemory, /* gcvTASK_UNMAP_MEMORY */ +}; + +static gceSTATUS +_TaskLink( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + /* Cast the task pointer. */ + gcsTASK_LINK_PTR task = (gcsTASK_LINK_PTR) TaskHeader->task; + + /* Save the pointer to the container. */ + gcsTASK_CONTAINER_PTR container = TaskHeader->container; + + /* No more tasks in the list? */ + if (task->task == gcvNULL) + { + /* Reset the entry. */ + TaskHeader->container = gcvNULL; + TaskHeader->task = gcvNULL; + TaskHeader->link = gcvNULL; + } + else + { + /* Update the entry. */ + TaskHeader->container = task->cotainer; + TaskHeader->task = task->task; + } + + /* Decrement the task buffer reference. */ + gcmkASSERT(container->referenceCount >= 0); + if (container->referenceCount == 0) + { + /* Free the container. */ + _FreeTaskContainer(Command, container); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_TaskCluster( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + /* Cast the task pointer. */ + gcsTASK_CLUSTER_PTR cluster = (gcsTASK_CLUSTER_PTR) TaskHeader->task; + + /* Get the number of tasks. */ + gctUINT taskCount = cluster->taskCount; + + /* Advance to the next task. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (cluster + 1); + + /* Perform all tasks in the cluster. */ + while (taskCount) + { + /* Perform the current task. */ + gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( + Command, + TaskHeader + )); + + /* Update the task count. */ + taskCount -= 1; + } + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskIncrement( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_INCREMENT_PTR task = (gcsTASK_INCREMENT_PTR) TaskHeader->task; + + /* Convert physical into logical address. */ + gctUINT32_PTR logical; + gcmkERR_BREAK(gckOS_MapPhysical( + Command->os, + task->address, + gcmSIZEOF(gctUINT32), + (gctPOINTER *) &logical + )); + + /* Increment data. */ + (* logical) += 1; + + /* Unmap the physical memory. */ + gcmkERR_BREAK(gckOS_UnmapPhysical( + Command->os, + logical, + gcmSIZEOF(gctUINT32) + )); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskDecrement( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_DECREMENT_PTR task = (gcsTASK_DECREMENT_PTR) TaskHeader->task; + + /* Convert physical into logical address. */ + gctUINT32_PTR logical; + gcmkERR_BREAK(gckOS_MapPhysical( + Command->os, + task->address, + gcmSIZEOF(gctUINT32), + (gctPOINTER *) &logical + )); + + /* Decrement data. */ + (* logical) -= 1; + + /* Unmap the physical memory. */ + gcmkERR_BREAK(gckOS_UnmapPhysical( + Command->os, + logical, + gcmSIZEOF(gctUINT32) + )); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskSignal( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_SIGNAL_PTR task = (gcsTASK_SIGNAL_PTR) TaskHeader->task; + + + /* Map the signal into kernel space. */ +#ifdef __QNXNTO__ + gcmkERR_BREAK(gckOS_UserSignal( + Command->os, task->signal, task->rcvid, task->coid + )); +#else + gcmkERR_BREAK(gckOS_UserSignal( + Command->os, task->signal, task->process + )); +#endif /* __QNXNTO__ */ + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskLockdown( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + gctUINT32_PTR userCounter = gcvNULL; + gctUINT32_PTR kernelCounter = gcvNULL; + gctSIGNAL signal = gcvNULL; + + do + { + /* Cast the task pointer. */ + gcsTASK_LOCKDOWN_PTR task = (gcsTASK_LOCKDOWN_PTR) TaskHeader->task; + + /* Convert physical addresses into logical. */ + gcmkERR_BREAK(gckOS_MapPhysical( + Command->os, + task->userCounter, + gcmSIZEOF(gctUINT32), + (gctPOINTER *) &userCounter + )); + + gcmkERR_BREAK(gckOS_MapPhysical( + Command->os, + task->kernelCounter, + gcmSIZEOF(gctUINT32), + (gctPOINTER *) &kernelCounter + )); + + /* Update the kernel counter. */ + (* kernelCounter) += 1; + + /* Are the counters equal? */ + if ((* userCounter) == (* kernelCounter)) + { + /* Map the signal into kernel space. */ + gcmkERR_BREAK(gckOS_MapSignal( + Command->os, task->signal, task->process, &signal + )); + + if (signal == gcvNULL) + { + /* Signal. */ + gcmkERR_BREAK(gckOS_Signal( + Command->os, task->signal, gcvTRUE + )); + } + else + { + /* Signal. */ + gcmkERR_BREAK(gckOS_Signal( + Command->os, signal, gcvTRUE + )); + } + } + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Destroy the mapped signal. */ + if (signal != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySignal( + Command->os, signal + )); + } + + /* Unmap the physical memory. */ + if (kernelCounter != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapPhysical( + Command->os, + kernelCounter, + gcmSIZEOF(gctUINT32) + )); + } + + if (userCounter != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapPhysical( + Command->os, + userCounter, + gcmSIZEOF(gctUINT32) + )); + } + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskUnlockVideoMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_UNLOCK_VIDEO_MEMORY_PTR task + = (gcsTASK_UNLOCK_VIDEO_MEMORY_PTR) TaskHeader->task; + + /* Unlock video memory. */ + gcmkERR_BREAK(gckVIDMEM_Unlock( + Command->kernel->kernel, + task->node, + gcvSURF_TYPE_UNKNOWN, + gcvNULL)); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskFreeVideoMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_FREE_VIDEO_MEMORY_PTR task + = (gcsTASK_FREE_VIDEO_MEMORY_PTR) TaskHeader->task; + + /* Free video memory. */ + gcmkERR_BREAK(gckVIDMEM_Free(task->node)); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskFreeContiguousMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR task + = (gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR) TaskHeader->task; + + /* Free contiguous memory. */ + gcmkERR_BREAK(gckOS_FreeContiguous( + Command->os, task->physical, task->logical, task->bytes + )); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskUnmapUserMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_UNMAP_USER_MEMORY_PTR task + = (gcsTASK_UNMAP_USER_MEMORY_PTR) TaskHeader->task; + + /* Unmap the user memory. */ + gcmkERR_BREAK(gckOS_UnmapUserMemoryEx( + Command->os, gcvCORE_VG, task->memory, task->size, task->info, task->address + )); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_TaskUnmapMemory( + gckVGCOMMAND Command, + gcsBLOCK_TASK_ENTRY_PTR TaskHeader + ) +{ + gceSTATUS status; + + do + { + /* Cast the task pointer. */ + gcsTASK_UNMAP_MEMORY_PTR task + = (gcsTASK_UNMAP_MEMORY_PTR) TaskHeader->task; + + /* Unmap memory. */ + gcmkERR_BREAK(gckKERNEL_UnmapMemory( + Command->kernel->kernel, task->physical, task->bytes, task->logical + )); + + /* Update the reference counter. */ + TaskHeader->container->referenceCount -= 1; + + /* Update the task pointer. */ + TaskHeader->task = (gcsTASK_HEADER_PTR) (task + 1); + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +************ Hardware Block Interrupt Handlers For Scheduled Events ************ +\******************************************************************************/ + +static gceSTATUS +_EventHandler_Block( + IN gckVGKERNEL Kernel, + IN gcsBLOCK_TASK_ENTRY_PTR TaskHeader, + IN gctBOOL ProcessAll + ) +{ + gceSTATUS status, last; + + gcmkHEADER_ARG("Kernel=0x%x TaskHeader=0x%x ProcessAll=0x%x", Kernel, TaskHeader, ProcessAll); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + do + { + gckVGCOMMAND command; + + /* Get the command buffer object. */ + command = Kernel->command; + + /* Increment the interrupt usage semaphore. */ + gcmkERR_BREAK(gckOS_IncrementSemaphore( + command->os, TaskHeader->interruptSemaphore + )); + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + command->os, + command->taskMutex, + gcvINFINITE + )); + + /* Verify inputs. */ + gcmkASSERT(TaskHeader != gcvNULL); + gcmkASSERT(TaskHeader->container != gcvNULL); + gcmkASSERT(TaskHeader->task != gcvNULL); + gcmkASSERT(TaskHeader->link != gcvNULL); + + /* Process tasks. */ + do + { + /* Process the current task. */ + gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( + command, + TaskHeader + )); + + /* Is the next task is LINK? */ + if (TaskHeader->task->id == gcvTASK_LINK) + { + gcmkERR_BREAK(_taskRoutine[TaskHeader->task->id]( + command, + TaskHeader + )); + + /* Done. */ + break; + } + } + while (ProcessAll); + + /* Release the mutex. */ + gcmkCHECK_STATUS(gckOS_ReleaseMutex( + command->os, + command->taskMutex + )); + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +gcmDECLARE_INTERRUPT_HANDLER(COMMAND, 0) +{ + gceSTATUS status, last; + + gcmkHEADER_ARG("Kernel=0x%x ", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + + do + { + gckVGCOMMAND command; + gcsKERNEL_QUEUE_HEADER_PTR mergeQueue; + gcsKERNEL_QUEUE_HEADER_PTR queueTail; + gcsKERNEL_CMDQUEUE_PTR entry; + gctUINT entryCount; + + /* Get the command buffer object. */ + command = Kernel->command; + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + command->os, + command->queueMutex, + gcvINFINITE + )); + + /* Get the current queue. */ + queueTail = command->queueTail; + + /* Get the current queue entry. */ + entry = queueTail->currentEntry; + + /* Get the number of entries in the queue. */ + entryCount = queueTail->pending; + + /* Process all entries. */ + while (gcvTRUE) + { + /* Call post-execution function. */ + status = entry->handler(Kernel, entry); + + /* Failed? */ + if (gcmkIS_ERROR(status)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, + gcvZONE_COMMAND, + "[%s] line %d: post action failed.\n", + __FUNCTION__, __LINE__ + ); + } + + /* Executed the next buffer? */ + if (status == gcvSTATUS_EXECUTED) + { + /* Update the queue. */ + queueTail->pending = entryCount; + queueTail->currentEntry = entry; + + /* Success. */ + status = gcvSTATUS_OK; + + /* Break out of the loop. */ + break; + } + + /* Advance to the next entry. */ + entry += 1; + entryCount -= 1; + + /* Last entry? */ + if (entryCount == 0) + { + /* Reset the queue to idle. */ + queueTail->pending = 0; + + /* Get a shortcut to the queue to merge with. */ + mergeQueue = command->mergeQueue; + + /* Merge the queues if necessary. */ + if (mergeQueue != queueTail) + { + gcmkASSERT(mergeQueue < queueTail); + gcmkASSERT(mergeQueue->next == queueTail); + + mergeQueue->size + += gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + + queueTail->size; + + mergeQueue->next = queueTail->next; + } + + /* Advance to the next queue. */ + queueTail = queueTail->next; + + /* Did it wrap around? */ + if (command->queue == queueTail) + { + /* Reset merge queue. */ + command->mergeQueue = queueTail; + } + + /* Set new queue. */ + command->queueTail = queueTail; + + /* Is the next queue scheduled? */ + if (queueTail->pending > 0) + { + gcsCMDBUFFER_PTR commandBuffer; + + /* The first entry must be a command buffer. */ + commandBuffer = queueTail->currentEntry->commandBuffer; + + /* Start the command processor. */ + status = gckVGHARDWARE_Execute( + command->hardware, + commandBuffer->address, + commandBuffer->dataCount + ); + + /* Failed? */ + if (gcmkIS_ERROR(status)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, + gcvZONE_COMMAND, + "[%s] line %d: failed to start the next queue.\n", + __FUNCTION__, __LINE__ + ); + } + } +#if gcdPOWER_MANAGEMENT + else + { + + status = gckVGHARDWARE_SetPowerManagementState( + Kernel->command->hardware, gcvPOWER_IDLE_BROADCAST + ); + } +#endif + + /* Break out of the loop. */ + break; + } + } + + /* Release the mutex. */ + gcmkCHECK_STATUS(gckOS_ReleaseMutex( + command->os, + command->queueMutex + )); + } + while (gcvFALSE); + + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +/* Define standard block interrupt handlers. */ +gcmDEFINE_INTERRUPT_HANDLER(TESSELLATOR, 0) +gcmDEFINE_INTERRUPT_HANDLER(VG, 0) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 0) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 1) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 2) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 3) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 4) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 5) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 6) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 7) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 8) +gcmDEFINE_INTERRUPT_HANDLER(PIXEL, 9) + +/* The entries in the array are arranged by event priority. */ +static gcsBLOCK_INTERRUPT_HANDLER _blockHandlers[] = +{ + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(TESSELLATOR, 0), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(VG, 0), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 0), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 1), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 2), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 3), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 4), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 5), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 6), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 7), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 8), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(PIXEL, 9), + gcmDEFINE_INTERRUPT_HANDLER_ENTRY(COMMAND, 0), +}; + + +/******************************************************************************\ +************************* Static Command Buffer Handlers *********************** +\******************************************************************************/ + +static gceSTATUS +_UpdateStaticCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d)\n", + __FUNCTION__, __LINE__ + ); + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_ExecuteStaticCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gceSTATUS status; + + do + { + gcsCMDBUFFER_PTR commandBuffer; + + /* Cast the command buffer header. */ + commandBuffer = Entry->commandBuffer; + + /* Set to update the command buffer next time. */ + Entry->handler = _UpdateStaticCommandBuffer; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", + __FUNCTION__, __LINE__, + commandBuffer->address, + commandBuffer->dataCount + ); + + /* Start the command processor. */ + gcmkERR_BREAK(gckVGHARDWARE_Execute( + Kernel->hardware, + commandBuffer->address, + commandBuffer->dataCount + )); + + /* Success. */ + return gcvSTATUS_EXECUTED; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_UpdateLastStaticCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ +#if gcvDEBUG || gcdFORCE_MESSAGES + /* Get the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; + + /* Validate the command buffer. */ + gcmkASSERT(commandBuffer->completion != gcvNULL); + gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER); + +#endif + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): processing all tasks scheduled for FE.\n", + __FUNCTION__, __LINE__ + ); + + /* Perform scheduled tasks. */ + return _EventHandler_Block( + Kernel, + &Kernel->command->taskTable[gcvBLOCK_COMMAND], + gcvTRUE + ); +} + +static gceSTATUS +_ExecuteLastStaticCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gceSTATUS status; + + do + { + /* Cast the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; + + /* Set to update the command buffer next time. */ + Entry->handler = _UpdateLastStaticCommandBuffer; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", + __FUNCTION__, __LINE__, + commandBuffer->address, + commandBuffer->dataCount + ); + + /* Start the command processor. */ + gcmkERR_BREAK(gckVGHARDWARE_Execute( + Kernel->hardware, + commandBuffer->address, + commandBuffer->dataCount + )); + + /* Success. */ + return gcvSTATUS_EXECUTED; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +************************* Dynamic Command Buffer Handlers ********************** +\******************************************************************************/ + +static gceSTATUS +_UpdateDynamicCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d)\n", + __FUNCTION__, __LINE__ + ); + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_ExecuteDynamicCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gceSTATUS status; + + do + { + /* Cast the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; + + /* Set to update the command buffer next time. */ + Entry->handler = _UpdateDynamicCommandBuffer; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", + __FUNCTION__, __LINE__, + commandBuffer->address, + commandBuffer->dataCount + ); + + /* Start the command processor. */ + gcmkERR_BREAK(gckVGHARDWARE_Execute( + Kernel->hardware, + commandBuffer->address, + commandBuffer->dataCount + )); + + /* Success. */ + return gcvSTATUS_EXECUTED; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_UpdateLastDynamicCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ +#if gcvDEBUG || gcdFORCE_MESSAGES + /* Get the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; + + /* Validate the command buffer. */ + gcmkASSERT(commandBuffer->completion != gcvNULL); + gcmkASSERT(commandBuffer->completion != gcvVACANT_BUFFER); + +#endif + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): processing all tasks scheduled for FE.\n", + __FUNCTION__, __LINE__ + ); + + /* Perform scheduled tasks. */ + return _EventHandler_Block( + Kernel, + &Kernel->command->taskTable[gcvBLOCK_COMMAND], + gcvTRUE + ); +} + +static gceSTATUS +_ExecuteLastDynamicCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gceSTATUS status; + + do + { + /* Cast the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = Entry->commandBuffer; + + /* Set to update the command buffer next time. */ + Entry->handler = _UpdateLastDynamicCommandBuffer; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s(%d): executing next buffer @ 0x%08X, data count = %d\n", + __FUNCTION__, __LINE__, + commandBuffer->address, + commandBuffer->dataCount + ); + + /* Start the command processor. */ + gcmkERR_BREAK(gckVGHARDWARE_Execute( + Kernel->hardware, + commandBuffer->address, + commandBuffer->dataCount + )); + + /* Success. */ + return gcvSTATUS_EXECUTED; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +********************************* Other Handlers ******************************* +\******************************************************************************/ + +static gceSTATUS +_FreeKernelCommandBuffer( + IN gckVGKERNEL Kernel, + IN gcsKERNEL_CMDQUEUE_PTR Entry + ) +{ + gceSTATUS status; + + /* Free the command buffer. */ + status = _FreeCommandBuffer(Kernel, Entry->commandBuffer); + + /* Return status. */ + return status; +} + + +/******************************************************************************\ +******************************* Queue Management ******************************* +\******************************************************************************/ + +#if gcvDUMP_COMMAND_BUFFER +static void +_DumpCommandQueue( + IN gckVGCOMMAND Command, + IN gcsKERNEL_QUEUE_HEADER_PTR QueueHeader, + IN gctUINT EntryCount + ) +{ + gcsKERNEL_CMDQUEUE_PTR entry; + gctUINT queueIndex; + +#if defined(gcvCOMMAND_BUFFER_NAME) + static gctUINT arrayCount = 0; +#endif + + /* Is dumpinng enabled? */ + if (!Commad->enableDumping) + { + return; + } + +#if !defined(gcvCOMMAND_BUFFER_NAME) + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_COMMAND, + "COMMAND QUEUE DUMP: %d entries\n", EntryCount + ); +#endif + + /* Get the pointer to the first entry. */ + entry = QueueHeader->currentEntry; + + /* Iterate through the queue. */ + for (queueIndex = 0; queueIndex < EntryCount; queueIndex += 1) + { + gcsCMDBUFFER_PTR buffer; + gctUINT bufferCount; + gctUINT bufferIndex; + gctUINT i, count; + gctUINT size; + gctUINT32_PTR data; + +#if gcvDUMP_COMMAND_LINES + gctUINT lineNumber; +#endif + +#if !defined(gcvCOMMAND_BUFFER_NAME) + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_COMMAND, + "ENTRY %d\n", queueIndex + ); +#endif + + /* Reset the count. */ + bufferCount = 0; + + /* Set the initial buffer. */ + buffer = entry->commandBuffer; + + /* Loop through all subbuffers. */ + while (buffer) + { + /* Update the count. */ + bufferCount += 1; + + /* Advance to the next subbuffer. */ + buffer = buffer->nextSubBuffer; + } + +#if !defined(gcvCOMMAND_BUFFER_NAME) + if (bufferCount > 1) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + " COMMAND BUFFER SET: %d buffers.\n", + bufferCount + ); + } +#endif + + /* Reset the buffer index. */ + bufferIndex = 0; + + /* Set the initial buffer. */ + buffer = entry->commandBuffer; + + /* Loop through all subbuffers. */ + while (buffer) + { + /* Determine the size of the buffer. */ + size = buffer->dataCount * Command->info.commandAlignment; + +#if !defined(gcvCOMMAND_BUFFER_NAME) + /* A single buffer? */ + if (bufferCount == 1) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + " COMMAND BUFFER: count=%d (0x%X), size=%d bytes @ %08X.\n", + buffer->dataCount, + buffer->dataCount, + size, + buffer->address + ); + } + else + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + " COMMAND BUFFER %d: count=%d (0x%X), size=%d bytes @ %08X\n", + bufferIndex, + buffer->dataCount, + buffer->dataCount, + size, + buffer->address + ); + } +#endif + + /* Determine the number of double words to print. */ + count = size / 4; + + /* Determine the buffer location. */ + data = (gctUINT32_PTR) + ( + (gctUINT8_PTR) buffer + buffer->bufferOffset + ); + +#if defined(gcvCOMMAND_BUFFER_NAME) + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + "unsigned int _" gcvCOMMAND_BUFFER_NAME "_%d[] =\n", + arrayCount + ); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + "{\n" + ); + + arrayCount += 1; +#endif + +#if gcvDUMP_COMMAND_LINES + /* Reset the line number. */ + lineNumber = 0; +#endif + +#if defined(gcvCOMMAND_BUFFER_NAME) + count -= 2; +#endif + + for (i = 0; i < count; i += 1) + { + if ((i % 8) == 0) + { +#if defined(gcvCOMMAND_BUFFER_NAME) + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\t"); +#else + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " "); +#endif + } + +#if gcvDUMP_COMMAND_LINES + if (lineNumber == gcvDUMP_COMMAND_LINES) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, " . . . . . . . . .\n"); + break; + } +#endif + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "0x%08X", data[i]); + + if (i + 1 == count) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, "\n"); + +#if gcvDUMP_COMMAND_LINES + lineNumber += 1; +#endif + } + else + { + if (((i + 1) % 8) == 0) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ",\n"); + +#if gcvDUMP_COMMAND_LINES + lineNumber += 1; +#endif + } + else + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_COMMAND, ", "); + } + } + } + +#if defined(gcvCOMMAND_BUFFER_NAME) + gcmkTRACE_ZONE( + gcvLEVEL_INFO, + gcvZONE_COMMAND, + "};\n\n" + ); +#endif + + /* Advance to the next subbuffer. */ + buffer = buffer->nextSubBuffer; + bufferIndex += 1; + } + + /* Advance to the next entry. */ + entry += 1; + } +} +#endif + +static gceSTATUS +_LockCurrentQueue( + IN gckVGCOMMAND Command, + OUT gcsKERNEL_CMDQUEUE_PTR * Entries, + OUT gctUINT_PTR EntryCount + ) +{ + gceSTATUS status; + + do + { + gcsKERNEL_QUEUE_HEADER_PTR queueHead; + + /* Get a shortcut to the head of the queue. */ + queueHead = Command->queueHead; + + /* Is the head buffer still being worked on? */ + if (queueHead->pending) + { + /* Increment overflow count. */ + Command->queueOverflow += 1; + + /* Wait until the head becomes idle. */ + gcmkERR_BREAK(_WaitForIdle(Command, queueHead)); + } + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + Command->os, + Command->queueMutex, + gcvINFINITE + )); + + /* Determine the first queue entry. */ + queueHead->currentEntry = (gcsKERNEL_CMDQUEUE_PTR) + ( + (gctUINT8_PTR) queueHead + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + ); + + /* Set the pointer to the first entry. */ + * Entries = queueHead->currentEntry; + + /* Determine the number of available entries. */ + * EntryCount = queueHead->size / gcmSIZEOF(gcsKERNEL_CMDQUEUE); + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + +static gceSTATUS +_UnlockCurrentQueue( + IN gckVGCOMMAND Command, + IN gctUINT EntryCount + ) +{ + gceSTATUS status; + + do + { +#if !gcdENABLE_INFINITE_SPEED_HW + gcsKERNEL_QUEUE_HEADER_PTR queueTail; + gcsKERNEL_QUEUE_HEADER_PTR queueHead; + gcsKERNEL_QUEUE_HEADER_PTR queueNext; + gctUINT queueSize; + gctUINT newSize; + gctUINT unusedSize; + + /* Get shortcut to the head and to the tail of the queue. */ + queueTail = Command->queueTail; + queueHead = Command->queueHead; + + /* Dump the command buffer. */ +#if gcvDUMP_COMMAND_BUFFER + _DumpCommandQueue(Command, queueHead, EntryCount); +#endif + + /* Get a shortcut to the current queue size. */ + queueSize = queueHead->size; + + /* Determine the new queue size. */ + newSize = EntryCount * gcmSIZEOF(gcsKERNEL_CMDQUEUE); + gcmkASSERT(newSize <= queueSize); + + /* Determine the size of the unused area. */ + unusedSize = queueSize - newSize; + + /* Is the unused area big enough to become a buffer? */ + if (unusedSize >= gcvMINUMUM_BUFFER) + { + gcsKERNEL_QUEUE_HEADER_PTR nextHead; + + /* Place the new header. */ + nextHead = (gcsKERNEL_QUEUE_HEADER_PTR) + ( + (gctUINT8_PTR) queueHead + + gcmSIZEOF(gcsKERNEL_QUEUE_HEADER) + + newSize + ); + + /* Initialize the buffer. */ + nextHead->size = unusedSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER); + nextHead->pending = 0; + + /* Link the buffer in. */ + nextHead->next = queueHead->next; + queueHead->next = nextHead; + queueNext = nextHead; + + /* Update the size of the current buffer. */ + queueHead->size = newSize; + } + + /* Not big enough. */ + else + { + /* Determine the next queue. */ + queueNext = queueHead->next; + } + + /* Mark the buffer as busy. */ + queueHead->pending = EntryCount; + + /* Advance to the next buffer. */ + Command->queueHead = queueNext; + + /* Start the command processor if the queue was empty. */ + if (queueTail == queueHead) + { + gcsCMDBUFFER_PTR commandBuffer; + + /* The first entry must be a command buffer. */ + commandBuffer = queueTail->currentEntry->commandBuffer; + + /* Start the command processor. */ + gcmkERR_BREAK(gckVGHARDWARE_Execute( + Command->hardware, + commandBuffer->address, + commandBuffer->dataCount + )); + } + + /* The queue was not empty. */ + else + { + /* Advance the merge buffer if needed. */ + if (queueHead == Command->mergeQueue) + { + Command->mergeQueue = queueNext; + } + } +#endif + + /* Release the mutex. */ + gcmkERR_BREAK(gckOS_ReleaseMutex( + Command->os, + Command->queueMutex + )); + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + return status; +} + + + +/******************************************************************************\ +****************************** gckVGCOMMAND API Code ***************************** +\******************************************************************************/ +gceSTATUS +gckVGCOMMAND_Construct( + IN gckVGKERNEL Kernel, + IN gctUINT TaskGranularity, + IN gctUINT QueueSize, + OUT gckVGCOMMAND * Command + ) +{ + gceSTATUS status, last; + gckVGCOMMAND command = gcvNULL; + gcsKERNEL_QUEUE_HEADER_PTR queue; + gctUINT i, j; + + gcmkHEADER_ARG("Kernel=0x%x TaskGranularity=0x%x QueueSize=0x%x Command=0x%x", + Kernel, TaskGranularity, QueueSize, Command); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(QueueSize >= gcvMINUMUM_BUFFER); + gcmkVERIFY_ARGUMENT(Command != gcvNULL); + + do + { + /*********************************************************************** + ** Generic object initialization. + */ + + /* Allocate the gckVGCOMMAND structure. */ + gcmkERR_BREAK(gckOS_Allocate( + Kernel->os, + gcmSIZEOF(struct _gckVGCOMMAND), + (gctPOINTER *) &command + )); + + /* Initialize the object. */ + command->object.type = gcvOBJ_COMMAND; + + /* Set the object pointers. */ + command->kernel = Kernel; + command->os = Kernel->os; + command->hardware = Kernel->hardware; + + /* Reset pointers. */ + command->queue = gcvNULL; + command->queueMutex = gcvNULL; + command->taskMutex = gcvNULL; + command->commitMutex = gcvNULL; + + command->powerStallBuffer = gcvNULL; + command->powerStallSignal = gcvNULL; + command->powerSemaphore = gcvNULL; + + /* Reset context states. */ + command->contextCounter = 0; + command->currentContext = 0; + + /* Enable command buffer dumping. */ + command->enableDumping = gcvTRUE; + + /* Set features. */ + command->fe20 = Kernel->hardware->fe20; + command->vg20 = Kernel->hardware->vg20; + command->vg21 = Kernel->hardware->vg21; + + /* Reset task table .*/ + gcmkVERIFY_OK(gckOS_ZeroMemory( + command->taskTable, gcmSIZEOF(command->taskTable) + )); + + /* Query command buffer attributes. */ + gcmkERR_BREAK(gckVGCOMMAND_InitializeInfo(command)); + + /* Create the control mutexes. */ + gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->queueMutex)); + gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->taskMutex)); + gcmkERR_BREAK(gckOS_CreateMutex(Kernel->os, &command->commitMutex)); + + /* Create the power management semaphore. */ + gcmkERR_BREAK(gckOS_CreateSemaphore(Kernel->os, + &command->powerSemaphore)); + + gcmkERR_BREAK(gckOS_CreateSignal(Kernel->os, + gcvFALSE, &command->powerStallSignal)); + + /*********************************************************************** + ** Command queue initialization. + */ + + /* Allocate the command queue. */ + gcmkERR_BREAK(gckOS_Allocate( + Kernel->os, + QueueSize, + (gctPOINTER *) &command->queue + )); + + /* Initialize the command queue. */ + queue = command->queue; + + queue->size = QueueSize - gcmSIZEOF(gcsKERNEL_QUEUE_HEADER); + queue->pending = 0; + queue->next = queue; + + command->queueHead = + command->queueTail = + command->mergeQueue = command->queue; + + command->queueOverflow = 0; + + + /*********************************************************************** + ** Enable TS overflow interrupt. + */ + + gcmkERR_BREAK(gckVGINTERRUPT_Enable( + Kernel->interrupt, + &command->info.tsOverflowInt, + _EventHandler_TSOverflow + )); + + /* Mask out the interrupt. */ + Kernel->hardware->eventMask &= ~(1 << command->info.tsOverflowInt); + + + /*********************************************************************** + ** Enable Bus Error interrupt. + */ + + /* Hardwired to bit 31. */ + command->busErrorInt = 31; + + /* Enable the interrupt. */ + gcmkERR_BREAK(gckVGINTERRUPT_Enable( + Kernel->interrupt, + &command->busErrorInt, + _EventHandler_BusError + )); + +#if gcdPOWER_MANAGEMENT + command->powerStallInt = 30; + /* Enable the interrupt. */ + gcmkERR_BREAK(gckVGINTERRUPT_Enable( + Kernel->interrupt, + &command->powerStallInt, + _EventHandler_PowerStall + )); +#endif + + /*********************************************************************** + ** Task management initialization. + */ + + command->taskStorage = gcvNULL; + command->taskStorageGranularity = TaskGranularity; + command->taskStorageUsable = TaskGranularity - gcmSIZEOF(gcsTASK_STORAGE); + + command->taskFreeHead = gcvNULL; + command->taskFreeTail = gcvNULL; + + /* Enable block handlers. */ + for (i = 0; i < gcmCOUNTOF(_blockHandlers); i += 1) + { + /* Get the target hardware block. */ + gceBLOCK block = _blockHandlers[i].block; + + /* Get the interrupt array entry. */ + gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[block]; + + /* Determine the interrupt value index. */ + gctUINT index = entry->interruptCount; + + /* Create the block semaphore. */ + if (entry->interruptSemaphore == gcvNULL) + { + gcmkERR_BREAK(gckOS_CreateSemaphoreVG( + command->os, &entry->interruptSemaphore + )); + } + + /* Enable auto-detection. */ + entry->interruptArray[index] = -1; + + /* Enable interrupt for the block. */ + gcmkERR_BREAK(gckVGINTERRUPT_Enable( + Kernel->interrupt, + &entry->interruptArray[index], + _blockHandlers[i].handler + )); + + /* Update the number of registered interrupts. */ + entry->interruptCount += 1; + + /* Inrement the semaphore to allow the usage of the registered + interrupt. */ + gcmkERR_BREAK(gckOS_IncrementSemaphore( + command->os, entry->interruptSemaphore + )); + + } + + /* Error? */ + if (gcmkIS_ERROR(status)) + { + break; + } + + /* Get the FE interrupt. */ + command->info.feBufferInt + = command->taskTable[gcvBLOCK_COMMAND].interruptArray[0]; + + /* Return gckVGCOMMAND object pointer. */ + *Command = command; + + gcmkFOOTER_ARG("*Command=0x%x",*Command); + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (command != gcvNULL) + { + /* Disable block handlers. */ + for (i = 0; i < gcvBLOCK_COUNT; i += 1) + { + /* Get the task table entry. */ + gcsBLOCK_TASK_ENTRY_PTR entry = &command->taskTable[i]; + + /* Destroy the semaphore. */ + if (entry->interruptSemaphore != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_DestroySemaphore( + command->os, entry->interruptSemaphore + )); + } + + /* Disable all enabled interrupts. */ + for (j = 0; j < entry->interruptCount; j += 1) + { + /* Must be a valid value. */ + gcmkASSERT(entry->interruptArray[j] >= 0); + gcmkASSERT(entry->interruptArray[j] <= 31); + + /* Disable the interrupt. */ + gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( + Kernel->interrupt, + entry->interruptArray[j] + )); + } + } + + /* Disable the bus error interrupt. */ + gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( + Kernel->interrupt, + command->busErrorInt + )); + + /* Disable TS overflow interrupt. */ + if (command->info.tsOverflowInt != -1) + { + gcmkCHECK_STATUS(gckVGINTERRUPT_Disable( + Kernel->interrupt, + command->info.tsOverflowInt + )); + } + + /* Delete the commit mutex. */ + if (command->commitMutex != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_DeleteMutex( + Kernel->os, command->commitMutex + )); + } + + /* Delete the command queue mutex. */ + if (command->taskMutex != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_DeleteMutex( + Kernel->os, command->taskMutex + )); + } + + /* Delete the command queue mutex. */ + if (command->queueMutex != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_DeleteMutex( + Kernel->os, command->queueMutex + )); + } + + /* Delete the command queue. */ + if (command->queue != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_Free( + Kernel->os, command->queue + )); + } + + if (command->powerSemaphore != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DestroySemaphore( + Kernel->os, command->powerSemaphore)); + } + + if (command->powerStallSignal != gcvNULL) + { + /* Create the power management semaphore. */ + gcmkVERIFY_OK(gckOS_DestroySignal( + Kernel->os, + command->powerStallSignal)); + } + + /* Free the gckVGCOMMAND structure. */ + gcmkCHECK_STATUS(gckOS_Free( + Kernel->os, command + )); + } + + gcmkFOOTER(); + /* Return the error. */ + return status; +} + +gceSTATUS +gckVGCOMMAND_Destroy( + OUT gckVGCOMMAND Command + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Command=0x%x", Command); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + + do + { + gctUINT i; + gcsTASK_STORAGE_PTR nextStorage; + + if (Command->queueHead != gcvNULL) + { + /* Wait until the head becomes idle. */ + gcmkERR_BREAK(_WaitForIdle(Command, Command->queueHead)); + } + + /* Disable block handlers. */ + for (i = 0; i < gcvBLOCK_COUNT; i += 1) + { + /* Get the interrupt array entry. */ + gcsBLOCK_TASK_ENTRY_PTR entry = &Command->taskTable[i]; + + /* Determine the index of the last interrupt in the array. */ + gctINT index = entry->interruptCount - 1; + + /* Destroy the semaphore. */ + if (entry->interruptSemaphore != gcvNULL) + { + gcmkERR_BREAK(gckOS_DestroySemaphore( + Command->os, entry->interruptSemaphore + )); + } + + /* Disable all enabled interrupts. */ + while (index >= 0) + { + /* Must be a valid value. */ + gcmkASSERT(entry->interruptArray[index] >= 0); + gcmkASSERT(entry->interruptArray[index] <= 31); + + /* Disable the interrupt. */ + gcmkERR_BREAK(gckVGINTERRUPT_Disable( + Command->kernel->interrupt, + entry->interruptArray[index] + )); + + /* Update to the next interrupt. */ + index -= 1; + entry->interruptCount -= 1; + } + + /* Error? */ + if (gcmkIS_ERROR(status)) + { + break; + } + } + + /* Error? */ + if (gcmkIS_ERROR(status)) + { + break; + } + + /* Disable the bus error interrupt. */ + gcmkERR_BREAK(gckVGINTERRUPT_Disable( + Command->kernel->interrupt, + Command->busErrorInt + )); + + /* Disable TS overflow interrupt. */ + if (Command->info.tsOverflowInt != -1) + { + gcmkERR_BREAK(gckVGINTERRUPT_Disable( + Command->kernel->interrupt, + Command->info.tsOverflowInt + )); + + Command->info.tsOverflowInt = -1; + } + + /* Delete the commit mutex. */ + if (Command->commitMutex != gcvNULL) + { + gcmkERR_BREAK(gckOS_DeleteMutex( + Command->os, Command->commitMutex + )); + + Command->commitMutex = gcvNULL; + } + + /* Delete the command queue mutex. */ + if (Command->taskMutex != gcvNULL) + { + gcmkERR_BREAK(gckOS_DeleteMutex( + Command->os, Command->taskMutex + )); + + Command->taskMutex = gcvNULL; + } + + /* Delete the command queue mutex. */ + if (Command->queueMutex != gcvNULL) + { + gcmkERR_BREAK(gckOS_DeleteMutex( + Command->os, Command->queueMutex + )); + + Command->queueMutex = gcvNULL; + } + + if (Command->powerSemaphore != gcvNULL) + { + /* Destroy the power management semaphore. */ + gcmkERR_BREAK(gckOS_DestroySemaphore( + Command->os, Command->powerSemaphore)); + } + + if (Command->powerStallSignal != gcvNULL) + { + /* Create the power management semaphore. */ + gcmkERR_BREAK(gckOS_DestroySignal( + Command->os, + Command->powerStallSignal)); + } + + if (Command->queue != gcvNULL) + { + /* Delete the command queue. */ + gcmkERR_BREAK(gckOS_Free( + Command->os, Command->queue + )); + } + + /* Destroy all allocated buffers. */ + while (Command->taskStorage) + { + /* Copy the buffer pointer. */ + nextStorage = Command->taskStorage->next; + + /* Free the current container. */ + gcmkERR_BREAK(gckOS_Free( + Command->os, Command->taskStorage + )); + + /* Advance to the next one. */ + Command->taskStorage = nextStorage; + } + + /* Error? */ + if (gcmkIS_ERROR(status)) + { + break; + } + + /* Mark the object as unknown. */ + Command->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVGCOMMAND structure. */ + gcmkERR_BREAK(gckOS_Free(Command->os, Command)); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Restore the object type if failed. */ + Command->object.type = gcvOBJ_COMMAND; + + gcmkFOOTER(); + /* Return the error. */ + return status; +} + +gceSTATUS +gckVGCOMMAND_QueryCommandBuffer( + IN gckVGCOMMAND Command, + OUT gcsCOMMAND_BUFFER_INFO_PTR Information + ) +{ + gcmkHEADER_ARG("Command=0x%x Information=0x%x", Command, Information); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + gcmkVERIFY_ARGUMENT(Information != gcvNULL); + + /* Copy the information. */ + gcmkVERIFY_OK(gckOS_MemCopy( + Information, &Command->info, sizeof(gcsCOMMAND_BUFFER_INFO) + )); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckVGCOMMAND_Allocate( + IN gckVGCOMMAND Command, + IN gctSIZE_T Size, + OUT gcsCMDBUFFER_PTR * CommandBuffer, + OUT gctPOINTER * Data + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Command=0x%x Size=0x%x CommandBuffer=0x%x Data=0x%x", + Command, Size, CommandBuffer, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + do + { + /* Allocate the buffer. */ + gcmkERR_BREAK(_AllocateCommandBuffer(Command, Size, CommandBuffer)); + + /* Determine the data pointer. */ + * Data = (gctUINT8_PTR) (*CommandBuffer) + (* CommandBuffer)->bufferOffset; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +gceSTATUS +gckVGCOMMAND_Free( + IN gckVGCOMMAND Command, + IN gcsCMDBUFFER_PTR CommandBuffer + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x", + Command, CommandBuffer); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL); + + /* Free command buffer. */ + status = _FreeCommandBuffer(Command->kernel, CommandBuffer); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +gceSTATUS +gckVGCOMMAND_Execute( + IN gckVGCOMMAND Command, + IN gcsCMDBUFFER_PTR CommandBuffer + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Command=0x%x CommandBuffer=0x%x", + Command, CommandBuffer); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + gcmkVERIFY_ARGUMENT(CommandBuffer != gcvNULL); + + do + { + gctUINT queueLength; + gcsKERNEL_CMDQUEUE_PTR kernelEntry; + + /* Lock the current queue. */ + gcmkERR_BREAK(_LockCurrentQueue( + Command, &kernelEntry, &queueLength + )); + + /* Set the buffer. */ + kernelEntry->commandBuffer = CommandBuffer; + kernelEntry->handler = _FreeKernelCommandBuffer; + + /* Lock the current queue. */ + gcmkERR_BREAK(_UnlockCurrentQueue( + Command, 1 + )); + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +gceSTATUS +gckVGCOMMAND_Commit( + IN gckVGCOMMAND Command, + IN gcsVGCONTEXT_PTR Context, + IN gcsVGCMDQUEUE_PTR Queue, + IN gctUINT EntryCount, + IN gcsTASK_MASTER_TABLE_PTR TaskTable + ) +{ + /* + The first buffer is executed through a direct gckVGHARDWARE_Execute call, + therefore only an update is needed after the execution is over. All + consequent buffers need to be executed upon the first update call from + the FE interrupt handler. + */ + + static gcsQUEUE_UPDATE_CONTROL _dynamicBuffer[] = + { + { + _UpdateDynamicCommandBuffer, + _UpdateDynamicCommandBuffer, + _UpdateLastDynamicCommandBuffer, + _UpdateLastDynamicCommandBuffer + }, + { + _ExecuteDynamicCommandBuffer, + _UpdateDynamicCommandBuffer, + _ExecuteLastDynamicCommandBuffer, + _UpdateLastDynamicCommandBuffer + } + }; + + static gcsQUEUE_UPDATE_CONTROL _staticBuffer[] = + { + { + _UpdateStaticCommandBuffer, + _UpdateStaticCommandBuffer, + _UpdateLastStaticCommandBuffer, + _UpdateLastStaticCommandBuffer + }, + { + _ExecuteStaticCommandBuffer, + _UpdateStaticCommandBuffer, + _ExecuteLastStaticCommandBuffer, + _UpdateLastStaticCommandBuffer + } + }; + + gceSTATUS status, last; + + gcmkHEADER_ARG("Command=0x%x Context=0x%x Queue=0x%x EntryCount=0x%x TaskTable=0x%x", + Command, Context, Queue, EntryCount, TaskTable); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Command, gcvOBJ_COMMAND); + gcmkVERIFY_ARGUMENT(Context != gcvNULL); + gcmkVERIFY_ARGUMENT(Queue != gcvNULL); + gcmkVERIFY_ARGUMENT(EntryCount > 1); + +#ifdef __QNXNTO__ + TaskTable->coid = Context->coid; + TaskTable->rcvid = Context->rcvid; +#endif /* __QNXNTO__ */ + + do + { + gctBOOL haveFETasks; + gctUINT queueSize; + gcsVGCMDQUEUE_PTR mappedQueue; + gcsVGCMDQUEUE_PTR userEntry; + gcsKERNEL_CMDQUEUE_PTR kernelEntry; + gcsQUEUE_UPDATE_CONTROL_PTR queueControl; + gctUINT currentLength; + gctUINT queueLength; + gctUINT entriesQueued; + gctUINT8_PTR previousEnd; + gctBOOL previousDynamic; + gctBOOL previousExecuted; + gctUINT controlIndex; + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + Command->os, + Command->commitMutex, + gcvINFINITE + )); + +#if gcdPOWER_MANAGEMENT + status = gckVGHARDWARE_SetPowerManagementState( + Command->hardware, gcvPOWER_ON_AUTO); + + if (gcmIS_ERROR(status)) + { + /* Acquire the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex( + Command->os, + Command->commitMutex + )); + + break; + } + /* Acquire the power semaphore. */ + status = gckOS_AcquireSemaphore( + Command->os, Command->powerSemaphore); + + if (gcmIS_ERROR(status)) + { + /* Acquire the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex( + Command->os, + Command->commitMutex + )); + + break; + } +#endif + do + { + /* Assign a context ID if not yet assigned. */ + if (Context->id == 0) + { + /* Assign the next context number. */ + Context->id = ++ Command->contextCounter; + + /* See if we overflowed. */ + if (Command->contextCounter == 0) + { + /* We actually did overflow, wow... */ + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + } + + /* The first entry in the queue is always the context buffer. + Verify whether the user context is the same as the current + context and if that's the case, skip the first entry. */ + if (Context->id == Command->currentContext) + { + /* Same context as before, skip the first entry. */ + EntryCount -= 1; + Queue += 1; + + /* Set the signal to avoid user waiting. */ +#ifdef __QNXNTO__ + gcmkERR_BREAK(gckOS_UserSignal( + Command->os, Context->signal, Context->rcvid, Context->coid + )); +#else + gcmkERR_BREAK(gckOS_UserSignal( + Command->os, Context->signal, Context->process + )); + +#endif /* __QNXNTO__ */ + + } + else + { + /* Different user context - keep the first entry. + Set the user context as the current one. */ + Command->currentContext = Context->id; + } + + /* Reset pointers. */ + queueControl = gcvNULL; + previousEnd = gcvNULL; + + /* Determine whether there are FE tasks to be performed. */ + haveFETasks = (TaskTable->table[gcvBLOCK_COMMAND].head != gcvNULL); + + /* Determine the size of the queue. */ + queueSize = EntryCount * gcmSIZEOF(gcsVGCMDQUEUE); + + /* Map the command queue into the kernel space. */ + gcmkERR_BREAK(gckOS_MapUserPointer( + Command->os, + Queue, + queueSize, + (gctPOINTER *) &mappedQueue + )); + + /* Set the first entry. */ + userEntry = mappedQueue; + + /* Process the command queue. */ + while (EntryCount) + { + /* Lock the current queue. */ + gcmkERR_BREAK(_LockCurrentQueue( + Command, &kernelEntry, &queueLength + )); + + /* Determine the number of entries to process. */ + currentLength = (queueLength < EntryCount) + ? queueLength + : EntryCount; + + /* Update the number of the entries left to process. */ + EntryCount -= currentLength; + + /* Reset previous flags. */ + previousDynamic = gcvFALSE; + previousExecuted = gcvFALSE; + + /* Set the initial control index. */ + controlIndex = 0; + + /* Process entries. */ + for (entriesQueued = 0; entriesQueued < currentLength; entriesQueued += 1) + { + /* Get the kernel pointer to the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer = gcvNULL; + gcmkERR_BREAK(_ConvertUserCommandBufferPointer( + Command, + userEntry->commandBuffer, + &commandBuffer + )); + + /* Is it a dynamic command buffer? */ + if (userEntry->dynamic) + { + /* Select dynamic buffer control functions. */ + queueControl = &_dynamicBuffer[controlIndex]; + } + + /* No, a static command buffer. */ + else + { + /* Select static buffer control functions. */ + queueControl = &_staticBuffer[controlIndex]; + } + + /* Set the command buffer pointer to the entry. */ + kernelEntry->commandBuffer = commandBuffer; + + /* If the previous entry was a dynamic command buffer, + link it to the current. */ + if (previousDynamic) + { + gcmkERR_BREAK(gckVGCOMMAND_FetchCommand( + Command, + previousEnd, + commandBuffer->address, + commandBuffer->dataCount, + gcvNULL + )); + + /* The buffer will be auto-executed, only need to + update it after it has been executed. */ + kernelEntry->handler = queueControl->update; + + /* The buffer is only being updated. */ + previousExecuted = gcvFALSE; + } + else + { + /* Set the buffer up for execution. */ + kernelEntry->handler = queueControl->execute; + + /* The buffer is being updated. */ + previousExecuted = gcvTRUE; + } + + /* The current buffer's END command becomes the last END. */ + previousEnd + = ((gctUINT8_PTR) commandBuffer) + + commandBuffer->bufferOffset + + commandBuffer->dataCount * Command->info.commandAlignment + - Command->info.staticTailSize; + + /* Update the last entry info. */ + previousDynamic = userEntry->dynamic; + + /* Advance entries. */ + userEntry += 1; + kernelEntry += 1; + + /* Update the control index. */ + controlIndex = 1; + } + + /* If the previous entry was a dynamic command buffer, + terminate it with an END. */ + if (previousDynamic) + { + gcmkERR_BREAK(gckVGCOMMAND_EndCommand( + Command, + previousEnd, + Command->info.feBufferInt, + gcvNULL + )); + } + + /* Last buffer? */ + if (EntryCount == 0) + { + /* Modify the last command buffer's routines to handle + tasks if any.*/ + if (haveFETasks) + { + if (previousExecuted) + { + kernelEntry[-1].handler = queueControl->lastExecute; + } + else + { + kernelEntry[-1].handler = queueControl->lastUpdate; + } + } + + /* Release the mutex. */ + gcmkERR_BREAK(gckOS_ReleaseMutex( + Command->os, + Command->queueMutex + )); + /* Schedule tasks. */ + gcmkERR_BREAK(_ScheduleTasks(Command, TaskTable, previousEnd)); + + /* Acquire the mutex. */ + gcmkERR_BREAK(gckOS_AcquireMutex( + Command->os, + Command->queueMutex, + gcvINFINITE + )); + } + + /* Unkock and schedule the current queue for execution. */ + gcmkERR_BREAK(_UnlockCurrentQueue( + Command, currentLength + )); + } + + + /* Unmap the user command buffer. */ + gcmkERR_BREAK(gckOS_UnmapUserPointer( + Command->os, + Queue, + queueSize, + mappedQueue + )); + } + while (gcvFALSE); + +#if gcdPOWER_MANAGEMENT + gcmkVERIFY_OK(gckOS_ReleaseSemaphore( + Command->os, Command->powerSemaphore)); +#endif + /* Release the mutex. */ + gcmkCHECK_STATUS(gckOS_ReleaseMutex( + Command->os, + Command->commitMutex + )); + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +#endif /* gcdENABLE_VG */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_db.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_db.c new file mode 100644 index 0000000..ca53c74 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_db.c @@ -0,0 +1,1423 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_DATABASE + +/******************************************************************************* +***** Private fuctions ********************************************************/ + +/******************************************************************************* +** gckKERNEL_NewDatabase +** +** Create a new database structure and insert it to the head of the hash list. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** ProcessID that identifies the database. +** +** OUTPUT: +** +** gcsDATABASE_PTR * Database +** Pointer to a variable receiving the database structure pointer on +** success. +*/ +static gceSTATUS +gckKERNEL_NewDatabase( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + OUT gcsDATABASE_PTR * Database + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + gctBOOL acquired = gcvFALSE; + gctSIZE_T slot; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); + + /* Acquire the database mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + if (Kernel->db->freeDatabase != gcvNULL) + { + /* Allocate a database from the free list. */ + database = Kernel->db->freeDatabase; + Kernel->db->freeDatabase = database->next; + } + else + { + gctPOINTER pointer = gcvNULL; + + /* Allocate a new database from the heap. */ + gcmkONERROR(gckOS_Allocate(Kernel->os, + gcmSIZEOF(gcsDATABASE), + &pointer)); + + database = pointer; + } + + /* Compute the hash for the database. */ + slot = ProcessID % gcmCOUNTOF(Kernel->db->db); + + /* Insert the database into the hash. */ + database->next = Kernel->db->db[slot]; + Kernel->db->db[slot] = database; + + /* Save the hash slot. */ + database->slot = slot; + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Return the database. */ + *Database = database; + + /* Success. */ + gcmkFOOTER_ARG("*Database=0x%x", *Database); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_FindDatabase +** +** Find a database identified by a process ID and move it to the head of the +** hash list. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** ProcessID that identifies the database. +** +** gctBOOL LastProcessID +** gcvTRUE if searching for the last known process ID. gcvFALSE if +** we need to search for the process ID specified by the ProcessID +** argument. +** +** OUTPUT: +** +** gcsDATABASE_PTR * Database +** Pointer to a variable receiving the database structure pointer on +** success. +*/ +static gceSTATUS +gckKERNEL_FindDatabase( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gctBOOL LastProcessID, + OUT gcsDATABASE_PTR * Database + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database, previous; + gctSIZE_T slot; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d LastProcessID=%d", + Kernel, ProcessID, LastProcessID); + + /* Compute the hash for the database. */ + slot = ProcessID % gcmCOUNTOF(Kernel->db->db); + + /* Acquire the database mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Check whether we are getting the last known database. */ + if (LastProcessID) + { + /* Use last database. */ + database = Kernel->db->lastDatabase; + + if (database == gcvNULL) + { + /* Database not found. */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + } + else + { + /* Walk the hash list. */ + for (previous = gcvNULL, database = Kernel->db->db[slot]; + database != gcvNULL; + database = database->next) + { + if (database->processID == ProcessID) + { + /* Found it! */ + break; + } + + previous = database; + } + + if (database == gcvNULL) + { + /* Database not found. */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + + if (previous != gcvNULL) + { + /* Move database to the head of the hash list. */ + previous->next = database->next; + database->next = Kernel->db->db[slot]; + Kernel->db->db[slot] = database; + } + } + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Return the database. */ + *Database = database; + + /* Success. */ + gcmkFOOTER_ARG("*Database=0x%x", *Database); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_DeleteDatabase +** +** Remove a database from the hash list and delete its structure. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gcsDATABASE_PTR Database +** Pointer to the database structure to remove. +** +** OUTPUT: +** +** Nothing. +*/ +static gceSTATUS +gckKERNEL_DeleteDatabase( + IN gckKERNEL Kernel, + IN gcsDATABASE_PTR Database + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsDATABASE_PTR database; + + gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database); + + /* Acquire the database mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Check slot value. */ + gcmkVERIFY_ARGUMENT(Database->slot < gcmCOUNTOF(Kernel->db->db)); + + if (Database->slot < gcmCOUNTOF(Kernel->db->db)) + { + /* Check if database if the head of the hash list. */ + if (Kernel->db->db[Database->slot] == Database) + { + /* Remove the database from the hash list. */ + Kernel->db->db[Database->slot] = Database->next; + } + else + { + /* Walk the has list to find the database. */ + for (database = Kernel->db->db[Database->slot]; + database != gcvNULL; + database = database->next + ) + { + /* Check if the next list entry is this database. */ + if (database->next == Database) + { + /* Remove the database from the hash list. */ + database->next = Database->next; + break; + } + } + + if (database == gcvNULL) + { + /* Ouch! Something got corrupted. */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + } + } + + if (Kernel->db->lastDatabase != gcvNULL) + { + /* Insert database to the free list. */ + Kernel->db->lastDatabase->next = Kernel->db->freeDatabase; + Kernel->db->freeDatabase = Kernel->db->lastDatabase; + } + + /* Keep database as the last database. */ + Kernel->db->lastDatabase = Database; + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_NewRecord +** +** Create a new database record structure and insert it to the head of the +** database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gcsDATABASE_PTR Database +** Pointer to a database structure. +** +** OUTPUT: +** +** gcsDATABASE_RECORD_PTR * Record +** Pointer to a variable receiving the database record structure +** pointer on success. +*/ +static gceSTATUS +gckKERNEL_NewRecord( + IN gckKERNEL Kernel, + IN gcsDATABASE_PTR Database, + OUT gcsDATABASE_RECORD_PTR * Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsDATABASE_RECORD_PTR record = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x Database=0x%x", Kernel, Database); + + /* Acquire the database mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + if (Kernel->db->freeRecord != gcvNULL) + { + /* Allocate the record from the free list. */ + record = Kernel->db->freeRecord; + Kernel->db->freeRecord = record->next; + } + else + { + gctPOINTER pointer = gcvNULL; + + /* Allocate the record from the heap. */ + gcmkONERROR(gckOS_Allocate(Kernel->os, + gcmSIZEOF(gcsDATABASE_RECORD), + &pointer)); + + record = pointer; + } + + /* Insert the record in the database. */ + record->next = Database->list; + Database->list = record; + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Return the record. */ + *Record = record; + + /* Success. */ + gcmkFOOTER_ARG("*Record=0x%x", *Record); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + if (record != gcvNULL) + { + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_DeleteRecord +** +** Remove a database record from the database and delete its structure. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gcsDATABASE_PTR Database +** Pointer to a database structure. +** +** gceDATABASE_TYPE Type +** Type of the record to remove. +** +** gctPOINTER Data +** Data of the record to remove. +** +** OUTPUT: +** +** gctSIZE_T_PTR Bytes +** Pointer to a variable that receives the size of the record deleted. +** Can be gcvNULL if the size is not required. +*/ +static gceSTATUS +gckKERNEL_DeleteRecord( + IN gckKERNEL Kernel, + IN gcsDATABASE_PTR Database, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Data, + OUT gctSIZE_T_PTR Bytes OPTIONAL + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsDATABASE_RECORD_PTR record, previous; + + gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", + Kernel, Database, Type, Data); + + /* Acquire the database mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Scan the database for this record. */ + for (record = Database->list, previous = gcvNULL; + record != gcvNULL; + record = record->next + ) + { + if ((record->type == Type) + && (record->data == Data) + ) + { + /* Found it! */ + break; + } + + previous = record; + } + + if (record == gcvNULL) + { + /* Ouch! This record is not found? */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + + if (Bytes != gcvNULL) + { + /* Return size of record. */ + *Bytes = record->bytes; + } + + /* Remove record from database. */ + if (previous == gcvNULL) + { + Database->list = record->next; + } + else + { + previous->next = record->next; + } + + /* Insert record in free list. */ + record->next = Kernel->db->freeRecord; + Kernel->db->freeRecord = record; + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu", gcmOPT_VALUE(Bytes)); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_FindRecord +** +** Find a database record from the database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gcsDATABASE_PTR Database +** Pointer to a database structure. +** +** gceDATABASE_TYPE Type +** Type of the record to remove. +** +** gctPOINTER Data +** Data of the record to remove. +** +** OUTPUT: +** +** gctSIZE_T_PTR Bytes +** Pointer to a variable that receives the size of the record deleted. +** Can be gcvNULL if the size is not required. +*/ +static gceSTATUS +gckKERNEL_FindRecord( + IN gckKERNEL Kernel, + IN gcsDATABASE_PTR Database, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Data, + OUT gcsDATABASE_RECORD_PTR Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsDATABASE_RECORD_PTR record; + + gcmkHEADER_ARG("Kernel=0x%x Database=0x%x Type=%d Data=0x%x", + Kernel, Database, Type, Data); + + /* Acquire the database mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Kernel->os, Kernel->db->dbMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Scan the database for this record. */ + for (record = Database->list; + record != gcvNULL; + record = record->next + ) + { + if ((record->type == Type) + && (record->data == Data) + ) + { + /* Found it! */ + break; + } + } + + if (record == gcvNULL) + { + /* Ouch! This record is not found? */ + gcmkONERROR(gcvSTATUS_INVALID_DATA); + } + + if (Record != gcvNULL) + { + /* Return information of record. */ + gcmkONERROR( + gckOS_MemCopy(Record, record, sizeof(gcsDATABASE_RECORD))); + } + + /* Release the database mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + + /* Success. */ + gcmkFOOTER_ARG("Record=0x%x", Record); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the database mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Kernel->os, Kernel->db->dbMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + + +/******************************************************************************* +***** Public API **************************************************************/ + +/******************************************************************************* +** gckKERNEL_CreateProcessDB +** +** Create a new process database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_CreateProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Create a new database. */ + gcmkONERROR(gckKERNEL_NewDatabase(Kernel, ProcessID, &database)); + + /* Initialize the database. */ + database->processID = ProcessID; + database->vidMem.bytes = 0; + database->vidMem.maxBytes = 0; + database->vidMem.totalBytes = 0; + database->nonPaged.bytes = 0; + database->nonPaged.maxBytes = 0; + database->nonPaged.totalBytes = 0; + database->contiguous.bytes = 0; + database->contiguous.maxBytes = 0; + database->contiguous.totalBytes = 0; + database->mapMemory.bytes = 0; + database->mapMemory.maxBytes = 0; + database->mapMemory.totalBytes = 0; + database->mapUserMemory.bytes = 0; + database->mapUserMemory.maxBytes = 0; + database->mapUserMemory.totalBytes = 0; + database->list = gcvNULL; + +#if gcdSECURE_USER + { + gctINT slot; + gcskSECURE_CACHE * cache = &database->cache; + + /* Setup the linked list of cache nodes. */ + for (slot = 1; slot <= gcdSECURE_CACHE_SLOTS; ++slot) + { + cache->cache[slot].logical = gcvNULL; + +#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE + cache->cache[slot].prev = &cache->cache[slot - 1]; + cache->cache[slot].next = &cache->cache[slot + 1]; +# endif +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + cache->cache[slot].nextHash = gcvNULL; + cache->cache[slot].prevHash = gcvNULL; +# endif + } + +#if gcdSECURE_CACHE_METHOD != gcdSECURE_CACHE_TABLE + /* Setup the head and tail of the cache. */ + cache->cache[0].next = &cache->cache[1]; + cache->cache[0].prev = &cache->cache[gcdSECURE_CACHE_SLOTS]; + cache->cache[0].logical = gcvNULL; + + /* Fix up the head and tail pointers. */ + cache->cache[0].next->prev = &cache->cache[0]; + cache->cache[0].prev->next = &cache->cache[0]; +# endif + +#if gcdSECURE_CACHE_METHOD == gcdSECURE_CACHE_HASH + /* Zero out the hash table. */ + for (slot = 0; slot < gcmCOUNTOF(cache->hash); ++slot) + { + cache->hash[slot].logical = gcvNULL; + cache->hash[slot].nextHash = gcvNULL; + } +# endif + + /* Initialize cache index. */ + cache->cacheIndex = gcvNULL; + cache->cacheFree = 1; + cache->cacheStamp = 0; + } +#endif + + /* Reset idle timer. */ + Kernel->db->lastIdle = 0; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_AddProcessDB +** +** Add a record to a process database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** gceDATABASE_TYPE TYPE +** Type of the record to add. +** +** gctPOINTER Pointer +** Data of the record to add. +** +** gctPHYS_ADDR Physical +** Physical address of the record to add. +** +** gctSIZE_T Size +** Size of the record to add. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_AddProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Size + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + gcsDATABASE_RECORD_PTR record = gcvNULL; + gcsDATABASE_COUNTERS * count; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x " + "Physical=0x%x Size=%lu", + Kernel, ProcessID, Type, Pointer, Physical, Size); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Special case the idle record. */ + if (Type == gcvDB_IDLE) + { + gctUINT64 time; + + /* Get the current profile time. */ + gcmkONERROR(gckOS_GetProfileTick(&time)); + + if ((ProcessID == 0) && (Kernel->db->lastIdle != 0)) + { + /* Out of idle, adjust time it was idle. */ + Kernel->db->idleTime += time - Kernel->db->lastIdle; + Kernel->db->lastIdle = 0; + } + else if (ProcessID == 1) + { + /* Save current idle time. */ + Kernel->db->lastIdle = time; + } + +#if gcdDYNAMIC_SPEED + { + /* Test for first call. */ + if (Kernel->db->lastSlowdown == 0) + { + /* Save milliseconds. */ + Kernel->db->lastSlowdown = time; + Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; + } + else + { + /* Compute ellapsed time in milliseconds. */ + gctUINT delta = gckOS_ProfileToMS(time - Kernel->db->lastSlowdown); + + /* Test for end of period. */ + if (delta >= gcdDYNAMIC_SPEED) + { + /* Compute number of idle milliseconds. */ + gctUINT idle = gckOS_ProfileToMS( + Kernel->db->idleTime - Kernel->db->lastSlowdownIdle); + + /* Broadcast to slow down the GPU. */ + gcmkONERROR(gckOS_BroadcastCalibrateSpeed(Kernel->os, + Kernel->hardware, + idle, + delta)); + + /* Save current time. */ + Kernel->db->lastSlowdown = time; + Kernel->db->lastSlowdownIdle = Kernel->db->idleTime; + } + } + } +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + + /* Find the database. */ + gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); + + /* Create a new record in the database. */ + gcmkONERROR(gckKERNEL_NewRecord(Kernel, database, &record)); + + /* Initialize the record. */ + record->kernel = Kernel; + record->type = Type; + record->data = Pointer; + record->physical = Physical; + record->bytes = Size; + + /* Get pointer to counters. */ + switch (Type) + { + case gcvDB_VIDEO_MEMORY: + count = &database->vidMem; + break; + + case gcvDB_NON_PAGED: + count = &database->nonPaged; + break; + + case gcvDB_CONTIGUOUS: + count = &database->contiguous; + break; + + case gcvDB_MAP_MEMORY: + count = &database->mapMemory; + break; + + case gcvDB_MAP_USER_MEMORY: + count = &database->mapUserMemory; + break; + + default: + count = gcvNULL; + break; + } + + if (count != gcvNULL) + { + /* Adjust counters. */ + count->totalBytes += Size; + count->bytes += Size; + + if (count->bytes > count->maxBytes) + { + count->maxBytes = count->bytes; + } + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_RemoveProcessDB +** +** Remove a record from a process database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** gceDATABASE_TYPE TYPE +** Type of the record to remove. +** +** gctPOINTER Pointer +** Data of the record to remove. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_RemoveProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + gctSIZE_T bytes = 0; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", + Kernel, ProcessID, Type, Pointer); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + + /* Find the database. */ + gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); + + /* Delete the record. */ + gcmkONERROR( + gckKERNEL_DeleteRecord(Kernel, database, Type, Pointer, &bytes)); + + /* Update counters. */ + switch (Type) + { + case gcvDB_VIDEO_MEMORY: + database->vidMem.bytes -= bytes; + break; + + case gcvDB_NON_PAGED: + database->nonPaged.bytes -= bytes; + break; + + case gcvDB_CONTIGUOUS: + database->contiguous.bytes -= bytes; + break; + + case gcvDB_MAP_MEMORY: + database->mapMemory.bytes -= bytes; + break; + + case gcvDB_MAP_USER_MEMORY: + database->mapUserMemory.bytes -= bytes; + break; + + default: + break; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_FindProcessDB +** +** Find a record from a process database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** gceDATABASE_TYPE TYPE +** Type of the record to remove. +** +** gctPOINTER Pointer +** Data of the record to remove. +** +** OUTPUT: +** +** gcsDATABASE_RECORD_PTR Record +** Copy of record. +*/ +gceSTATUS +gckKERNEL_FindProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gctUINT32 ThreadID, + IN gceDATABASE_TYPE Type, + IN gctPOINTER Pointer, + OUT gcsDATABASE_RECORD_PTR Record + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Pointer=0x%x", + Kernel, ProcessID, ThreadID, Type, Pointer); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + + /* Find the database. */ + gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); + + /* Find the record. */ + gcmkONERROR( + gckKERNEL_FindRecord(Kernel, database, Type, Pointer, Record)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_DestroyProcessDB +** +** Destroy a process database. If the database contains any records, the data +** inside those records will be deleted as well. This aids in the cleanup if +** a process has died unexpectedly or has memory leaks. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_DestroyProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + gcsDATABASE_RECORD_PTR record, next; + gctBOOL asynchronous; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Find the database. */ + gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): VidMem: total=%lu max=%lu", + ProcessID, database->vidMem.totalBytes, + database->vidMem.maxBytes); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): NonPaged: total=%lu max=%lu", + ProcessID, database->nonPaged.totalBytes, + database->nonPaged.maxBytes); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): Contiguous: total=%lu max=%lu", + ProcessID, database->contiguous.totalBytes, + database->contiguous.maxBytes); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): Idle time=%llu", + ProcessID, Kernel->db->idleTime); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): Map: total=%lu max=%lu", + ProcessID, database->mapMemory.totalBytes, + database->mapMemory.maxBytes); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DATABASE, + "DB(%d): Map: total=%lu max=%lu", + ProcessID, database->mapUserMemory.totalBytes, + database->mapUserMemory.maxBytes); + + if (database->list != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "Process %d has entries in its database:", + ProcessID); + } + + /* Walk all records. */ + for (record = database->list; record != gcvNULL; record = next) + { + /* Next next record. */ + next = record->next; + + /* Dispatch on record type. */ + switch (record->type) + { + case gcvDB_VIDEO_MEMORY: + /* Free the video memory. */ + status = gckVIDMEM_Free(record->data); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: VIDEO_MEMORY 0x%x (status=%d)", + record->data, status); + break; + + case gcvDB_NON_PAGED: + /* Free the non paged memory. */ + status = gckOS_FreeNonPagedMemory(Kernel->os, + record->bytes, + record->physical, + record->data); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: NON_PAGED 0x%x, bytes=%lu (status=%d)", + record->data, record->bytes, status); + break; + + case gcvDB_CONTIGUOUS: + /* Free the contiguous memory. */ + status = gckOS_FreeContiguous(Kernel->os, + record->physical, + record->data, + record->bytes); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: CONTIGUOUS 0x%x bytes=%lu (status=%d)", + record->data, record->bytes, status); + break; + + case gcvDB_SIGNAL: +#if USE_NEW_LINUX_SIGNAL + status = gcvSTATUS_NOT_SUPPORTED; +#else + /* Free the user signal. */ + status = gckOS_DestroyUserSignal(Kernel->os, + gcmPTR2INT(record->data)); +#endif /* USE_NEW_LINUX_SIGNAL */ + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: SIGNAL %d (status=%d)", + (gctINT) record->data, status); + break; + + case gcvDB_VIDEO_MEMORY_LOCKED: + /* Unlock what we still locked */ + status = gckVIDMEM_Unlock(record->kernel, + record->data, + gcvSURF_TYPE_UNKNOWN, + &asynchronous); + + if (gcmIS_SUCCESS(status) && (gcvTRUE == asynchronous)) + { + /* TODO: we maybe need to schedule a event here */ + status = gckVIDMEM_Unlock(record->kernel, + record->data, + gcvSURF_TYPE_UNKNOWN, + gcvNULL); + } + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: VIDEO_MEMORY_LOCKED 0x%x (status=%d)", + record->data, status); + break; + + case gcvDB_CONTEXT: + /* TODO: Free the context */ + status = gckCOMMAND_Detach(Kernel->command, record->data); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: CONTEXT 0x%x (status=%d)", + record->data, status); + break; + + case gcvDB_MAP_MEMORY: + /* Unmap memory. */ + status = gckKERNEL_UnmapMemory(Kernel, + record->physical, + record->bytes, + record->data); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: MAP MEMORY %d (status=%d)", + gcmPTR2INT(record->data), status); + break; + + case gcvDB_MAP_USER_MEMORY: + /* TODO: Unmap user memory. */ + status = gckOS_UnmapUserMemoryEx(Kernel->os, + Kernel->core, + record->data, + record->bytes, + record->physical, + 0); + + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_DATABASE, + "DB: MAP USER MEMORY %d (status=%d)", + gcmPTR2INT(record->data), status); + break; + + case gcvDB_SHARED_INFO: + status = gckOS_FreeMemory(Kernel->os, record->physical); + break; + + default: + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_DATABASE, + "DB: Correcupted record=0x%08x type=%d", + record, record->type); + break; + } + + /* Delete the record. */ + gcmkONERROR(gckKERNEL_DeleteRecord(Kernel, + database, + record->type, + record->data, + gcvNULL)); + } + + /* Delete the database. */ + gcmkONERROR(gckKERNEL_DeleteDatabase(Kernel, database)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckKERNEL_QueryProcessDB +** +** Query a process database for the current usage of a particular record type. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** gctBOOL LastProcessID +** gcvTRUE if searching for the last known process ID. gcvFALSE if +** we need to search for the process ID specified by the ProcessID +** argument. +** +** gceDATABASE_TYPE Type +** Type of the record to query. +** +** OUTPUT: +** +** gcuDATABASE_INFO * Info +** Pointer to a variable that receives the requested information. +*/ +gceSTATUS +gckKERNEL_QueryProcessDB( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + IN gctBOOL LastProcessID, + IN gceDATABASE_TYPE Type, + OUT gcuDATABASE_INFO * Info + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d Type=%d Info=0x%x", + Kernel, ProcessID, Type, Info); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + /* Find the database. */ + gcmkONERROR( + gckKERNEL_FindDatabase(Kernel, ProcessID, LastProcessID, &database)); + + /* Get pointer to counters. */ + switch (Type) + { + case gcvDB_VIDEO_MEMORY: + gcmkONERROR(gckOS_MemCopy(&Info->counters, + &database->vidMem, + gcmSIZEOF(database->vidMem))); + break; + + case gcvDB_NON_PAGED: + gcmkONERROR(gckOS_MemCopy(&Info->counters, + &database->nonPaged, + gcmSIZEOF(database->vidMem))); + break; + + case gcvDB_CONTIGUOUS: + gcmkONERROR(gckOS_MemCopy(&Info->counters, + &database->contiguous, + gcmSIZEOF(database->vidMem))); + break; + + case gcvDB_IDLE: + Info->time = Kernel->db->idleTime; + Kernel->db->idleTime = 0; + break; + + case gcvDB_MAP_MEMORY: + gcmkONERROR(gckOS_MemCopy(&Info->counters, + &database->mapMemory, + gcmSIZEOF(database->mapMemory))); + break; + + case gcvDB_MAP_USER_MEMORY: + gcmkONERROR(gckOS_MemCopy(&Info->counters, + &database->mapUserMemory, + gcmSIZEOF(database->mapUserMemory))); + break; + + default: + break; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +/******************************************************************************* +** gckKERNEL_GetProcessDBCache +** +** Get teh secure cache from a process database. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to a gckKERNEL object. +** +** gctUINT32 ProcessID +** Process ID used to identify the database. +** +** OUTPUT: +** +** gcskSECURE_CACHE_PTR * Cache +** Pointer to a variable that receives the secure cache pointer. +*/ +gceSTATUS +gckKERNEL_GetProcessDBCache( + IN gckKERNEL Kernel, + IN gctUINT32 ProcessID, + OUT gcskSECURE_CACHE_PTR * Cache + ) +{ + gceSTATUS status; + gcsDATABASE_PTR database; + + gcmkHEADER_ARG("Kernel=0x%x ProcessID=%d", Kernel, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Cache != gcvNULL); + + /* Find the database. */ + gcmkONERROR(gckKERNEL_FindDatabase(Kernel, ProcessID, gcvFALSE, &database)); + + /* Return the pointer to the cache. */ + *Cache = &database->cache; + + /* Success. */ + gcmkFOOTER_ARG("*Cache=0x%x", *Cache); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_debug.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_debug.c new file mode 100644 index 0000000..77ea27a --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_debug.c @@ -0,0 +1,2557 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include <gc_hal_kernel_debug.h> + +/******************************************************************************\ +******************************** Debug Variables ******************************* +\******************************************************************************/ + +static gceSTATUS _lastError = gcvSTATUS_OK; +static gctUINT32 _debugLevel = gcvLEVEL_ERROR; +/* +_debugZones config value +Please Reference define in gc_hal_base.h +*/ +static gctUINT32 _debugZones = gcvZONE_NONE; + +/******************************************************************************\ +********************************* Debug Switches ******************************* +\******************************************************************************/ + +/* + gcdBUFFERED_OUTPUT + + When set to non-zero, all output is collected into a buffer with the + specified size. Once the buffer gets full, the debug buffer will be + printed to the console. gcdBUFFERED_SIZE determines the size of the buffer. +*/ +#define gcdBUFFERED_OUTPUT 0 + +/* + gcdBUFFERED_SIZE + + When set to non-zero, all output is collected into a buffer with the + specified size. Once the buffer gets full, the debug buffer will be + printed to the console. +*/ +#define gcdBUFFERED_SIZE (1024 * 1024 * 2) + +/* + gcdDMA_BUFFER_COUNT + + If greater then zero, the debugger will attempt to find the command buffer + where DMA is currently executing and then print this buffer and + (gcdDMA_BUFFER_COUNT - 1) buffers before the current one. If set to zero + or the current buffer is not found, all buffers are printed. +*/ +#define gcdDMA_BUFFER_COUNT 0 + +/* + gcdTHREAD_BUFFERS + + When greater then one, will accumulate messages from the specified number + of threads in separate output buffers. +*/ +#define gcdTHREAD_BUFFERS 1 + +/* + gcdENABLE_OVERFLOW + + When set to non-zero, and the output buffer gets full, instead of being + printed, it will be allowed to overflow removing the oldest messages. +*/ +#define gcdENABLE_OVERFLOW 1 + +/* + gcdSHOW_LINE_NUMBER + + When enabledm each print statement will be preceeded with the current + line number. +*/ +#define gcdSHOW_LINE_NUMBER 0 + +/* + gcdSHOW_PROCESS_ID + + When enabledm each print statement will be preceeded with the current + process ID. +*/ +#define gcdSHOW_PROCESS_ID 0 + +/* + gcdSHOW_THREAD_ID + + When enabledm each print statement will be preceeded with the current + thread ID. +*/ +#define gcdSHOW_THREAD_ID 0 + +/* + gcdSHOW_TIME + + When enabled each print statement will be preceeded with the current + high-resolution time. +*/ +#define gcdSHOW_TIME 0 + + +/******************************************************************************\ +****************************** Miscellaneous Macros **************************** +\******************************************************************************/ + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) +# define gcmDBGASSERT(Expression, Format, Value) \ + if (!(Expression)) \ + { \ + _DirectPrint( \ + "*** gcmDBGASSERT ***************************\n" \ + " function : %s\n" \ + " line : %d\n" \ + " expression : " #Expression "\n" \ + " actual value : " Format "\n", \ + __FUNCTION__, __LINE__, Value \ + ); \ + } +#else +# define gcmDBGASSERT(Expression, Format, Value) +#endif + +#define gcmPTRALIGNMENT(Pointer, Alignemnt) \ +( \ + gcmALIGN(gcmPTR2INT(Pointer), Alignemnt) - gcmPTR2INT(Pointer) \ +) + +#if gcdALIGNBYSIZE +# define gcmISALIGNED(Offset, Alignment) \ + (((Offset) & ((Alignment) - 1)) == 0) + +# define gcmkALIGNPTR(Type, Pointer, Alignment) \ + Pointer = (Type) gcmINT2PTR(gcmALIGN(gcmPTR2INT(Pointer), Alignment)) +#else +# define gcmISALIGNED(Offset, Alignment) \ + gcvTRUE + +# define gcmkALIGNPTR(Type, Pointer, Alignment) +#endif + +#define gcmALIGNSIZE(Offset, Size) \ + ((Size - Offset) + Size) + +#define gcdHAVEPREFIX \ +( \ + gcdSHOW_TIME \ + || gcdSHOW_LINE_NUMBER \ + || gcdSHOW_PROCESS_ID \ + || gcdSHOW_THREAD_ID \ +) + +#if gcdHAVEPREFIX + +# define gcdOFFSET 0 + +#if gcdSHOW_TIME +#if gcmISALIGNED(gcdOFFSET, 8) +# define gcdTIMESIZE gcmSIZEOF(gctUINT64) +# elif gcdOFFSET == 4 +# define gcdTIMESIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64)) +# else +# error "Unexpected offset value." +# endif +# undef gcdOFFSET +# define gcdOFFSET 8 +#if !defined(gcdPREFIX_LEADER) +# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64) +# define gcdTIMEFORMAT "0x%016llX" +# else +# define gcdTIMEFORMAT ", 0x%016llX" +# endif +# else +# define gcdTIMESIZE 0 +# define gcdTIMEFORMAT +# endif + +#if gcdSHOW_LINE_NUMBER +#if gcmISALIGNED(gcdOFFSET, 8) +# define gcdNUMSIZE gcmSIZEOF(gctUINT64) +# elif gcdOFFSET == 4 +# define gcdNUMSIZE gcmALIGNSIZE(4, gcmSIZEOF(gctUINT64)) +# else +# error "Unexpected offset value." +# endif +# undef gcdOFFSET +# define gcdOFFSET 8 +#if !defined(gcdPREFIX_LEADER) +# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT64) +# define gcdNUMFORMAT "%8llu" +# else +# define gcdNUMFORMAT ", %8llu" +# endif +# else +# define gcdNUMSIZE 0 +# define gcdNUMFORMAT +# endif + +#if gcdSHOW_PROCESS_ID +#if gcmISALIGNED(gcdOFFSET, 4) +# define gcdPIDSIZE gcmSIZEOF(gctUINT32) +# else +# error "Unexpected offset value." +# endif +# undef gcdOFFSET +# define gcdOFFSET 4 +#if !defined(gcdPREFIX_LEADER) +# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) +# define gcdPIDFORMAT "pid=%5d" +# else +# define gcdPIDFORMAT ", pid=%5d" +# endif +# else +# define gcdPIDSIZE 0 +# define gcdPIDFORMAT +# endif + +#if gcdSHOW_THREAD_ID +#if gcmISALIGNED(gcdOFFSET, 4) +# define gcdTIDSIZE gcmSIZEOF(gctUINT32) +# else +# error "Unexpected offset value." +# endif +# undef gcdOFFSET +# define gcdOFFSET 4 +#if !defined(gcdPREFIX_LEADER) +# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) +# define gcdTIDFORMAT "tid=%5d" +# else +# define gcdTIDFORMAT ", tid=%5d" +# endif +# else +# define gcdTIDSIZE 0 +# define gcdTIDFORMAT +# endif + +# define gcdPREFIX_SIZE \ + ( \ + gcdTIMESIZE \ + + gcdNUMSIZE \ + + gcdPIDSIZE \ + + gcdTIDSIZE \ + ) + + static const char * _prefixFormat = + "[" + gcdTIMEFORMAT + gcdNUMFORMAT + gcdPIDFORMAT + gcdTIDFORMAT + "] "; + +#else + +# define gcdPREFIX_LEADER gcmSIZEOF(gctUINT32) +# define gcdPREFIX_SIZE 0 + +#endif + +/* Assumed largest variable argument leader size. */ +#define gcdVARARG_LEADER gcmSIZEOF(gctUINT64) + +/* Alignnments. */ +#if gcdALIGNBYSIZE +# define gcdPREFIX_ALIGNMENT gcdPREFIX_LEADER +# define gcdVARARG_ALIGNMENT gcdVARARG_LEADER +#else +# define gcdPREFIX_ALIGNMENT 0 +# define gcdVARARG_ALIGNMENT 0 +#endif + +#if gcdBUFFERED_OUTPUT +# define gcdOUTPUTPREFIX _AppendPrefix +# define gcdOUTPUTSTRING _AppendString +# define gcdOUTPUTCOPY _AppendCopy +# define gcdOUTPUTBUFFER _AppendBuffer +#else +# define gcdOUTPUTPREFIX _PrintPrefix +# define gcdOUTPUTSTRING _PrintString +# define gcdOUTPUTCOPY _PrintString +# define gcdOUTPUTBUFFER _PrintBuffer +#endif + +/******************************************************************************\ +****************************** Private Structures ****************************** +\******************************************************************************/ + +typedef enum _gceBUFITEM +{ + gceBUFITEM_NONE, + gcvBUFITEM_PREFIX, + gcvBUFITEM_STRING, + gcvBUFITEM_COPY, + gcvBUFITEM_BUFFER +} +gceBUFITEM; + +/* Common item head/buffer terminator. */ +typedef struct _gcsBUFITEM_HEAD * gcsBUFITEM_HEAD_PTR; +typedef struct _gcsBUFITEM_HEAD +{ + gceBUFITEM type; +} +gcsBUFITEM_HEAD; + +/* String prefix (for ex. [ 1,tid=0x019A]) */ +typedef struct _gcsBUFITEM_PREFIX * gcsBUFITEM_PREFIX_PTR; +typedef struct _gcsBUFITEM_PREFIX +{ + gceBUFITEM type; +#if gcdHAVEPREFIX + gctPOINTER prefixData; +#endif +} +gcsBUFITEM_PREFIX; + +/* Buffered string. */ +typedef struct _gcsBUFITEM_STRING * gcsBUFITEM_STRING_PTR; +typedef struct _gcsBUFITEM_STRING +{ + gceBUFITEM type; + gctINT indent; + gctCONST_STRING message; + gctPOINTER messageData; + gctUINT messageDataSize; +} +gcsBUFITEM_STRING; + +/* Buffered string (copy of the string is included with the record). */ +typedef struct _gcsBUFITEM_COPY * gcsBUFITEM_COPY_PTR; +typedef struct _gcsBUFITEM_COPY +{ + gceBUFITEM type; + gctINT indent; + gctPOINTER messageData; + gctUINT messageDataSize; +} +gcsBUFITEM_COPY; + +/* Memory buffer. */ +typedef struct _gcsBUFITEM_BUFFER * gcsBUFITEM_BUFFER_PTR; +typedef struct _gcsBUFITEM_BUFFER +{ + gceBUFITEM type; + gctINT indent; + gceDUMP_BUFFER bufferType; + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) + gctUINT32 dmaAddress; +#endif + + gctUINT dataSize; + gctUINT32 address; +#if gcdHAVEPREFIX + gctPOINTER prefixData; +#endif +} +gcsBUFITEM_BUFFER; + +typedef struct _gcsBUFFERED_OUTPUT * gcsBUFFERED_OUTPUT_PTR; +typedef struct _gcsBUFFERED_OUTPUT +{ +#if gcdTHREAD_BUFFERS > 1 + gctUINT32 threadID; +#endif + +#if gcdSHOW_LINE_NUMBER + gctUINT64 lineNumber; +#endif + + gctINT indent; + +#if gcdBUFFERED_OUTPUT + gctINT start; + gctINT index; + gctINT count; + gctUINT8 buffer[gcdBUFFERED_SIZE]; +#endif + + gcsBUFFERED_OUTPUT_PTR prev; + gcsBUFFERED_OUTPUT_PTR next; +} +gcsBUFFERED_OUTPUT; + +typedef gctUINT (* gcfPRINTSTRING) ( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ); + +typedef gctINT (* gcfGETITEMSIZE) ( + IN gcsBUFITEM_HEAD_PTR Item + ); + +/******************************************************************************\ +******************************* Private Variables ****************************** +\******************************************************************************/ + +static gcsBUFFERED_OUTPUT _outputBuffer[gcdTHREAD_BUFFERS]; +static gcsBUFFERED_OUTPUT_PTR _outputBufferHead = gcvNULL; +static gcsBUFFERED_OUTPUT_PTR _outputBufferTail = gcvNULL; + +/******************************************************************************\ +****************************** Item Size Functions ***************************** +\******************************************************************************/ + +#if gcdBUFFERED_OUTPUT +static gctINT +_GetTerminatorItemSize( + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + return gcmSIZEOF(gcsBUFITEM_HEAD); +} + +static gctINT +_GetPrefixItemSize( + IN gcsBUFITEM_HEAD_PTR Item + ) +{ +#if gcdHAVEPREFIX + gcsBUFITEM_PREFIX_PTR item = (gcsBUFITEM_PREFIX_PTR) Item; + gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); + return vlen + gcdPREFIX_SIZE; +#else + return gcmSIZEOF(gcsBUFITEM_PREFIX); +#endif +} + +static gctINT +_GetStringItemSize( + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + gcsBUFITEM_STRING_PTR item = (gcsBUFITEM_STRING_PTR) Item; + gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); + return vlen + item->messageDataSize; +} + +static gctINT +_GetCopyItemSize( + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + gcsBUFITEM_COPY_PTR item = (gcsBUFITEM_COPY_PTR) Item; + gctUINT vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); + return vlen + item->messageDataSize; +} + +static gctINT +_GetBufferItemSize( + IN gcsBUFITEM_HEAD_PTR Item + ) +{ +#if gcdHAVEPREFIX + gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item; + gctUINT vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); + return vlen + gcdPREFIX_SIZE + item->dataSize; +#else + gcsBUFITEM_BUFFER_PTR item = (gcsBUFITEM_BUFFER_PTR) Item; + return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize; +#endif +} + +static gcfGETITEMSIZE _itemSize[] = +{ + _GetTerminatorItemSize, + _GetPrefixItemSize, + _GetStringItemSize, + _GetCopyItemSize, + _GetBufferItemSize +}; +#endif + +/******************************************************************************\ +******************************* Printing Functions ***************************** +\******************************************************************************/ + +#if gcdDEBUG || gcdBUFFERED_OUTPUT +static void +_DirectPrint( + gctCONST_STRING Message, + ... + ) +{ + gctINT len; + char buffer[768]; + gctARGUMENTS arguments; + + gcmkARGUMENTS_START(arguments, Message); + len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), Message, arguments); + gcmkARGUMENTS_END(arguments); + + buffer[len] = '\0'; + gcmkOUTPUT_STRING(buffer); +} +#endif + +static int +_AppendIndent( + IN gctINT Indent, + IN char * Buffer, + IN int BufferSize + ) +{ + gctINT i; + + gctINT len = 0; + gctINT indent = Indent % 40; + + for (i = 0; i < indent; i += 1) + { + Buffer[len++] = ' '; + } + + if (indent != Indent) + { + len += gcmkSPRINTF( + Buffer + len, BufferSize - len, " <%d> ", Indent + ); + + Buffer[len] = '\0'; + } + + return len; +} + +#if gcdHAVEPREFIX +static void +_PrintPrefix( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctPOINTER Data + ) +{ + char buffer[768]; + gctINT len; + + /* Format the string. */ + len = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, Data); + buffer[len] = '\0'; + + /* Print the string. */ + gcmkOUTPUT_STRING(buffer); +} +#endif + +static void +_PrintString( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Indent, + IN gctCONST_STRING Message, + IN gctUINT ArgumentSize, + IN gctPOINTER Data + ) +{ + char buffer[768]; + gctINT len; + + /* Append the indent string. */ + len = _AppendIndent(Indent, buffer, gcmSIZEOF(buffer)); + + /* Format the string. */ + len += gcmkVSPRINTF(buffer + len, gcmSIZEOF(buffer) - len, Message, Data); + buffer[len] = '\0'; + + /* Add end-of-line if missing. */ + if (buffer[len - 1] != '\n') + { + buffer[len++] = '\n'; + buffer[len] = '\0'; + } + + /* Print the string. */ + gcmkOUTPUT_STRING(buffer); +} + +static void +_PrintBuffer( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Indent, + IN gctPOINTER PrefixData, + IN gctPOINTER Data, + IN gctUINT Address, + IN gctUINT DataSize, + IN gceDUMP_BUFFER Type, + IN gctUINT32 DmaAddress + ) +{ + static gctCONST_STRING _titleString[] = + { + "CONTEXT BUFFER", + "USER COMMAND BUFFER", + "KERNEL COMMAND BUFFER", + "LINK BUFFER", + "WAIT LINK BUFFER", + "" + }; + + static const gctINT COLUMN_COUNT = 8; + + gctUINT i, count, column, address; + gctUINT32_PTR data; + gctCHAR buffer[768]; + gctUINT indent, len; + gctBOOL command; + + /* Append space for the prefix. */ +#if gcdHAVEPREFIX + indent = gcmkVSPRINTF(buffer, gcmSIZEOF(buffer), _prefixFormat, PrefixData); + buffer[indent] = '\0'; +#else + indent = 0; +#endif + + /* Append the indent string. */ + indent += _AppendIndent( + Indent, buffer + indent, gcmSIZEOF(buffer) - indent + ); + + switch (Type) + { + case gceDUMP_BUFFER_CONTEXT: + case gceDUMP_BUFFER_USER: + case gceDUMP_BUFFER_KERNEL: + case gceDUMP_BUFFER_LINK: + case gceDUMP_BUFFER_WAITLINK: + /* Form and print the title string. */ + gcmkSPRINTF2( + buffer + indent, gcmSIZEOF(buffer) - indent, + "%s%s\n", _titleString[Type], + ((DmaAddress >= Address) && (DmaAddress < Address + DataSize)) + ? " (CURRENT)" : "" + ); + + gcmkOUTPUT_STRING(buffer); + + /* Terminate the string. */ + buffer[indent] = '\0'; + + /* This is a command buffer. */ + command = gcvTRUE; + break; + + case gceDUMP_BUFFER_FROM_USER: + /* This is not a command buffer. */ + command = gcvFALSE; + + /* No title. */ + break; + + default: + gcmDBGASSERT(gcvFALSE, "%s", "invalid buffer type"); + + /* This is not a command buffer. */ + command = gcvFALSE; + } + + /* Overwrite the prefix with spaces. */ + for (i = 0; i < indent; i += 1) + { + buffer[i] = ' '; + } + + /* Form and print the opening string. */ + if (command) + { + gcmkSPRINTF2( + buffer + indent, gcmSIZEOF(buffer) - indent, + "@[kernel.command %08X %08X\n", Address, DataSize + ); + + gcmkOUTPUT_STRING(buffer); + + /* Terminate the string. */ + buffer[indent] = '\0'; + } + + /* Get initial address. */ + address = Address; + + /* Cast the data pointer. */ + data = (gctUINT32_PTR) Data; + + /* Compute the number of double words. */ + count = DataSize / gcmSIZEOF(gctUINT32); + + /* Print the buffer. */ + for (i = 0, len = indent, column = 0; i < count; i += 1) + { + /* Append the address. */ + if (column == 0) + { + len += gcmkSPRINTF( + buffer + len, gcmSIZEOF(buffer) - len, "0x%08X:", address + ); + } + + /* Append the data value. */ + len += gcmkSPRINTF2( + buffer + len, gcmSIZEOF(buffer) - len, "%c%08X", + (address == DmaAddress)? '>' : ' ', data[i] + ); + + buffer[len] = '\0'; + + /* Update the address. */ + address += gcmSIZEOF(gctUINT32); + + /* Advance column count. */ + column += 1; + + /* End of line? */ + if ((column % COLUMN_COUNT) == 0) + { + /* Append EOL. */ + gcmkSTRCAT(buffer + len, gcmSIZEOF(buffer) - len, "\n"); + + /* Print the string. */ + gcmkOUTPUT_STRING(buffer); + + /* Reset. */ + len = indent; + column = 0; + } + } + + /* Print the last partial string. */ + if (column != 0) + { + /* Append EOL. */ + gcmkSTRCAT(buffer + len, gcmSIZEOF(buffer) - len, "\n"); + + /* Print the string. */ + gcmkOUTPUT_STRING(buffer); + } + + /* Form and print the opening string. */ + if (command) + { + buffer[indent] = '\0'; + gcmkSTRCAT(buffer, gcmSIZEOF(buffer), "] -- command\n"); + gcmkOUTPUT_STRING(buffer); + } +} + +#if gcdBUFFERED_OUTPUT +static gctUINT +_PrintNone( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + /* Return the size of the node. */ + return gcmSIZEOF(gcsBUFITEM_HEAD); +} + +static gctUINT +_PrintPrefixWrapper( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ) +{ +#if gcdHAVEPREFIX + gcsBUFITEM_PREFIX_PTR item; + gctUINT vlen; + + /* Get access to the data. */ + item = (gcsBUFITEM_PREFIX_PTR) Item; + + /* Print the message. */ + _PrintPrefix(OutputBuffer, item->prefixData); + + /* Compute the size of the variable portion of the structure. */ + vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); + + /* Return the size of the node. */ + return vlen + gcdPREFIX_SIZE; +#else + return gcmSIZEOF(gcsBUFITEM_PREFIX); +#endif +} + +static gctUINT +_PrintStringWrapper( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + gcsBUFITEM_STRING_PTR item; + gctUINT vlen; + + /* Get access to the data. */ + item = (gcsBUFITEM_STRING_PTR) Item; + + /* Print the message. */ + _PrintString( + OutputBuffer, + item->indent, item->message, item->messageDataSize, item->messageData + ); + + /* Compute the size of the variable portion of the structure. */ + vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); + + /* Return the size of the node. */ + return vlen + item->messageDataSize; +} + +static gctUINT +_PrintCopyWrapper( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ) +{ + gcsBUFITEM_COPY_PTR item; + gctCONST_STRING message; + gctUINT vlen; + + /* Get access to the data. */ + item = (gcsBUFITEM_COPY_PTR) Item; + + /* Determine the string pointer. */ + message = (gctCONST_STRING) (item + 1); + + /* Print the message. */ + _PrintString( + OutputBuffer, + item->indent, message, item->messageDataSize, item->messageData + ); + + /* Compute the size of the variable portion of the structure. */ + vlen = ((gctUINT8_PTR) item->messageData) - ((gctUINT8_PTR) item); + + /* Return the size of the node. */ + return vlen + item->messageDataSize; +} + +static gctUINT +_PrintBufferWrapper( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gcsBUFITEM_HEAD_PTR Item + ) +{ +#if gcdHAVEPREFIX + gctUINT32 dmaAddress; + gcsBUFITEM_BUFFER_PTR item; + gctPOINTER data; + gctUINT vlen; + + /* Get access to the data. */ + item = (gcsBUFITEM_BUFFER_PTR) Item; + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) + dmaAddress = item->dmaAddress; +#else + dmaAddress = 0xFFFFFFFF; +#endif + + if (dmaAddress != 0) + { + /* Compute the data address. */ + data = ((gctUINT8_PTR) item->prefixData) + gcdPREFIX_SIZE; + + /* Print buffer. */ + _PrintBuffer( + OutputBuffer, + item->indent, item->prefixData, + data, item->address, item->dataSize, + item->bufferType, dmaAddress + ); + } + + /* Compute the size of the variable portion of the structure. */ + vlen = ((gctUINT8_PTR) item->prefixData) - ((gctUINT8_PTR) item); + + /* Return the size of the node. */ + return vlen + gcdPREFIX_SIZE + item->dataSize; +#else + gctUINT32 dmaAddress; + gcsBUFITEM_BUFFER_PTR item; + + /* Get access to the data. */ + item = (gcsBUFITEM_BUFFER_PTR) Item; + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) + dmaAddress = item->dmaAddress; +#else + dmaAddress = 0xFFFFFFFF; +#endif + + if (dmaAddress != 0) + { + /* Print buffer. */ + _PrintBuffer( + OutputBuffer, + item->indent, gcvNULL, + item + 1, item->address, item->dataSize, + item->bufferType, dmaAddress + ); + } + + /* Return the size of the node. */ + return gcmSIZEOF(gcsBUFITEM_BUFFER) + item->dataSize; +#endif +} + +static gcfPRINTSTRING _printArray[] = +{ + _PrintNone, + _PrintPrefixWrapper, + _PrintStringWrapper, + _PrintCopyWrapper, + _PrintBufferWrapper +}; +#endif + +/******************************************************************************\ +******************************* Private Functions ****************************** +\******************************************************************************/ + +#if gcdBUFFERED_OUTPUT + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) +static gcsBUFITEM_BUFFER_PTR +_FindCurrentDMABuffer( + gctUINT32 DmaAddress + ) +{ + gctINT i, skip; + gcsBUFITEM_HEAD_PTR item; + gcsBUFITEM_BUFFER_PTR dmaCurrent; + + /* Reset the current buffer. */ + dmaCurrent = gcvNULL; + + /* Get the first stored item. */ + item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; + + /* Run through all items. */ + for (i = 0; i < _outputBufferHead->count; i += 1) + { + /* Buffer item? */ + if (item->type == gcvBUFITEM_BUFFER) + { + gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item; + + if ((DmaAddress >= buffer->address) && + (DmaAddress < buffer->address + buffer->dataSize)) + { + dmaCurrent = buffer; + } + } + + /* Get the item size and skip it. */ + skip = (* _itemSize[item->type]) (item); + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + + /* End of the buffer? Wrap around. */ + if (item->type == gceBUFITEM_NONE) + { + item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; + } + } + + /* Return result. */ + return dmaCurrent; +} + +static void +_EnableAllDMABuffers( + void + ) +{ + gctINT i, skip; + gcsBUFITEM_HEAD_PTR item; + + /* Get the first stored item. */ + item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; + + /* Run through all items. */ + for (i = 0; i < _outputBufferHead->count; i += 1) + { + /* Buffer item? */ + if (item->type == gcvBUFITEM_BUFFER) + { + gcsBUFITEM_BUFFER_PTR buffer = (gcsBUFITEM_BUFFER_PTR) item; + + /* Enable the buffer. */ + buffer->dmaAddress = ~0U; + } + + /* Get the item size and skip it. */ + skip = (* _itemSize[item->type]) (item); + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + + /* End of the buffer? Wrap around. */ + if (item->type == gceBUFITEM_NONE) + { + item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; + } + } +} + +static void +_EnableDMABuffers( + gctUINT32 DmaAddress, + gcsBUFITEM_BUFFER_PTR CurrentDMABuffer + ) +{ + gctINT i, skip, index; + gcsBUFITEM_HEAD_PTR item; + gcsBUFITEM_BUFFER_PTR buffers[gcdDMA_BUFFER_COUNT]; + + /* Reset buffer pointers. */ + gckOS_ZeroMemory(buffers, gcmSIZEOF(buffers)); + + /* Set the current buffer index. */ + index = -1; + + /* Get the first stored item. */ + item = (gcsBUFITEM_HEAD_PTR) &_outputBufferHead->buffer[_outputBufferHead->start]; + + /* Run through all items until the current DMA buffer is found. */ + for (i = 0; i < _outputBufferHead->count; i += 1) + { + /* Buffer item? */ + if (item->type == gcvBUFITEM_BUFFER) + { + /* Advance the index. */ + index = (index + 1) % gcdDMA_BUFFER_COUNT; + + /* Add to the buffer array. */ + buffers[index] = (gcsBUFITEM_BUFFER_PTR) item; + + /* Stop if this is the current DMA buffer. */ + if ((gcsBUFITEM_BUFFER_PTR) item == CurrentDMABuffer) + { + break; + } + } + + /* Get the item size and skip it. */ + skip = (* _itemSize[item->type]) (item); + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + + /* End of the buffer? Wrap around. */ + if (item->type == gceBUFITEM_NONE) + { + item = (gcsBUFITEM_HEAD_PTR) _outputBufferHead->buffer; + } + } + + /* Enable the found buffers. */ + gcmDBGASSERT(index != -1, "%d", index); + + for (i = 0; i < gcdDMA_BUFFER_COUNT; i += 1) + { + if (buffers[index] == gcvNULL) + { + break; + } + + buffers[index]->dmaAddress = DmaAddress; + + index -= 1; + + if (index == -1) + { + index = gcdDMA_BUFFER_COUNT - 1; + } + } +} +#endif + +static void +_Flush( + gctUINT32 DmaAddress + ) +{ + gctINT i, skip; + gcsBUFITEM_HEAD_PTR item; + + gcsBUFFERED_OUTPUT_PTR outputBuffer = _outputBufferHead; + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) + if ((outputBuffer != gcvNULL) && (outputBuffer->count != 0)) + { + /* Find the current DMA buffer. */ + gcsBUFITEM_BUFFER_PTR dmaCurrent = _FindCurrentDMABuffer(DmaAddress); + + /* Was the current buffer found? */ + if (dmaCurrent == gcvNULL) + { + /* No, print all buffers. */ + _EnableAllDMABuffers(); + } + else + { + /* Yes, enable only specified number of buffers. */ + _EnableDMABuffers(DmaAddress, dmaCurrent); + } + } +#endif + + while (outputBuffer != gcvNULL) + { + if (outputBuffer->count != 0) + { + _DirectPrint("********************************************************************************\n"); + _DirectPrint("FLUSHING DEBUG OUTPUT BUFFER (%d elements).\n", outputBuffer->count); + _DirectPrint("********************************************************************************\n"); + + item = (gcsBUFITEM_HEAD_PTR) &outputBuffer->buffer[outputBuffer->start]; + + for (i = 0; i < outputBuffer->count; i += 1) + { + skip = (* _printArray[item->type]) (outputBuffer, item); + + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + + if (item->type == gceBUFITEM_NONE) + { + item = (gcsBUFITEM_HEAD_PTR) outputBuffer->buffer; + } + } + + outputBuffer->start = 0; + outputBuffer->index = 0; + outputBuffer->count = 0; + } + + outputBuffer = outputBuffer->next; + } +} + +static gcsBUFITEM_HEAD_PTR +_AllocateItem( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Size + ) +{ + gctINT skip; + gcsBUFITEM_HEAD_PTR item, next; + +#if gcdENABLE_OVERFLOW + if ( + (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) + || + ( + (OutputBuffer->index < OutputBuffer->start) && + (OutputBuffer->index + Size >= OutputBuffer->start) + ) + ) + { + if (OutputBuffer->index + Size >= gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) + { + if (OutputBuffer->index < OutputBuffer->start) + { + item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start]; + + while (item->type != gceBUFITEM_NONE) + { + skip = (* _itemSize[item->type]) (item); + + OutputBuffer->start += skip; + OutputBuffer->count -= 1; + + item->type = gceBUFITEM_NONE; + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + } + + OutputBuffer->start = 0; + } + + OutputBuffer->index = 0; + } + + item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->start]; + + while (OutputBuffer->start - OutputBuffer->index <= Size) + { + skip = (* _itemSize[item->type]) (item); + + OutputBuffer->start += skip; + OutputBuffer->count -= 1; + + item->type = gceBUFITEM_NONE; + item = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + skip); + + if (item->type == gceBUFITEM_NONE) + { + OutputBuffer->start = 0; + break; + } + } + } +#else + if (OutputBuffer->index + Size > gcdBUFFERED_SIZE - gcmSIZEOF(gcsBUFITEM_HEAD)) + { + _DirectPrint("\nMessage buffer full; forcing message flush.\n\n"); + _Flush(~0U); + } +#endif + + item = (gcsBUFITEM_HEAD_PTR) &OutputBuffer->buffer[OutputBuffer->index]; + + OutputBuffer->index += Size; + OutputBuffer->count += 1; + + next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) item + Size); + next->type = gceBUFITEM_NONE; + + return item; +} + +#if gcdALIGNBYSIZE +static void +_FreeExtraSpace( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctPOINTER Item, + IN gctINT ItemSize, + IN gctINT FreeSize + ) +{ + gcsBUFITEM_HEAD_PTR next; + + OutputBuffer->index -= FreeSize; + + next = (gcsBUFITEM_HEAD_PTR) ((gctUINT8_PTR) Item + ItemSize); + next->type = gceBUFITEM_NONE; +} +#endif + +#if gcdHAVEPREFIX +static void +_AppendPrefix( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctPOINTER Data + ) +{ + gctUINT8_PTR prefixData; + gcsBUFITEM_PREFIX_PTR item; + gctINT allocSize; + +#if gcdALIGNBYSIZE + gctUINT alignment; + gctINT size, freeSize; +#endif + + gcmDBGASSERT(Data != gcvNULL, "%p", Data); + + /* Determine the maximum item size. */ + allocSize + = gcmSIZEOF(gcsBUFITEM_PREFIX) + + gcdPREFIX_SIZE + + gcdPREFIX_ALIGNMENT; + + /* Allocate prefix item. */ + item = (gcsBUFITEM_PREFIX_PTR) _AllocateItem(OutputBuffer, allocSize); + + /* Compute the initial prefix data pointer. */ + prefixData = (gctUINT8_PTR) (item + 1); + + /* Align the data pointer as necessary. */ +#if gcdALIGNBYSIZE + alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT); + prefixData += alignment; +#endif + + /* Set item data. */ + item->type = gcvBUFITEM_PREFIX; + item->prefixData = prefixData; + + /* Copy argument value. */ + memcpy(prefixData, Data, gcdPREFIX_SIZE); + +#if gcdALIGNBYSIZE + /* Compute the actual node size. */ + size = gcmSIZEOF(gcsBUFITEM_PREFIX) + gcdPREFIX_SIZE + alignment; + + /* Free extra memory if any. */ + freeSize = allocSize - size; + if (freeSize != 0) + { + _FreeExtraSpace(OutputBuffer, item, size, freeSize); + } +#endif +} +#endif + +static void +_AppendString( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Indent, + IN gctCONST_STRING Message, + IN gctUINT ArgumentSize, + IN gctPOINTER Data + ) +{ + gctUINT8_PTR messageData; + gcsBUFITEM_STRING_PTR item; + gctINT allocSize; + +#if gcdALIGNBYSIZE + gctUINT alignment; + gctINT size, freeSize; +#endif + + /* Determine the maximum item size. */ + allocSize + = gcmSIZEOF(gcsBUFITEM_STRING) + + ArgumentSize + + gcdVARARG_ALIGNMENT; + + /* Allocate prefix item. */ + item = (gcsBUFITEM_STRING_PTR) _AllocateItem(OutputBuffer, allocSize); + + /* Compute the initial message data pointer. */ + messageData = (gctUINT8_PTR) (item + 1); + + /* Align the data pointer as necessary. */ +#if gcdALIGNBYSIZE + alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT); + messageData += alignment; +#endif + + /* Set item data. */ + item->type = gcvBUFITEM_STRING; + item->indent = Indent; + item->message = Message; + item->messageData = messageData; + item->messageDataSize = ArgumentSize; + + /* Copy argument value. */ + if (ArgumentSize != 0) + { + memcpy(messageData, Data, ArgumentSize); + } + +#if gcdALIGNBYSIZE + /* Compute the actual node size. */ + size = gcmSIZEOF(gcsBUFITEM_STRING) + ArgumentSize + alignment; + + /* Free extra memory if any. */ + freeSize = allocSize - size; + if (freeSize != 0) + { + _FreeExtraSpace(OutputBuffer, item, size, freeSize); + } +#endif +} + +static void +_AppendCopy( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Indent, + IN gctCONST_STRING Message, + IN gctUINT ArgumentSize, + IN gctPOINTER Data + ) +{ + gctUINT8_PTR messageData; + gcsBUFITEM_COPY_PTR item; + gctINT allocSize; + gctINT messageLength; + gctCONST_STRING message; + +#if gcdALIGNBYSIZE + gctUINT alignment; + gctINT size, freeSize; +#endif + + /* Get the length of the string. */ + messageLength = strlen(Message) + 1; + + /* Determine the maximum item size. */ + allocSize + = gcmSIZEOF(gcsBUFITEM_COPY) + + messageLength + + ArgumentSize + + gcdVARARG_ALIGNMENT; + + /* Allocate prefix item. */ + item = (gcsBUFITEM_COPY_PTR) _AllocateItem(OutputBuffer, allocSize); + + /* Determine the message placement. */ + message = (gctCONST_STRING) (item + 1); + + /* Compute the initial message data pointer. */ + messageData = (gctUINT8_PTR) message + messageLength; + + /* Align the data pointer as necessary. */ +#if gcdALIGNBYSIZE + if (ArgumentSize == 0) + { + alignment = 0; + } + else + { + alignment = gcmPTRALIGNMENT(messageData, gcdVARARG_ALIGNMENT); + messageData += alignment; + } +#endif + + /* Set item data. */ + item->type = gcvBUFITEM_COPY; + item->indent = Indent; + item->messageData = messageData; + item->messageDataSize = ArgumentSize; + + /* Copy the message. */ + memcpy((gctPOINTER) message, Message, messageLength); + + /* Copy argument value. */ + if (ArgumentSize != 0) + { + memcpy(messageData, Data, ArgumentSize); + } + +#if gcdALIGNBYSIZE + /* Compute the actual node size. */ + size + = gcmSIZEOF(gcsBUFITEM_COPY) + + messageLength + + ArgumentSize + + alignment; + + /* Free extra memory if any. */ + freeSize = allocSize - size; + if (freeSize != 0) + { + _FreeExtraSpace(OutputBuffer, item, size, freeSize); + } +#endif +} + +static void +_AppendBuffer( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctINT Indent, + IN gctPOINTER PrefixData, + IN gctPOINTER Data, + IN gctUINT Address, + IN gctUINT DataSize, + IN gceDUMP_BUFFER Type, + IN gctUINT32 DmaAddress + ) +{ +#if gcdHAVEPREFIX + gctUINT8_PTR prefixData; + gcsBUFITEM_BUFFER_PTR item; + gctINT allocSize; + gctPOINTER data; + +#if gcdALIGNBYSIZE + gctUINT alignment; + gctINT size, freeSize; +#endif + + gcmDBGASSERT(DataSize != 0, "%d", DataSize); + gcmDBGASSERT(Data != gcvNULL, "%p", Data); + + /* Determine the maximum item size. */ + allocSize + = gcmSIZEOF(gcsBUFITEM_BUFFER) + + gcdPREFIX_SIZE + + gcdPREFIX_ALIGNMENT + + DataSize; + + /* Allocate prefix item. */ + item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, allocSize); + + /* Compute the initial prefix data pointer. */ + prefixData = (gctUINT8_PTR) (item + 1); + +#if gcdALIGNBYSIZE + /* Align the data pointer as necessary. */ + alignment = gcmPTRALIGNMENT(prefixData, gcdPREFIX_ALIGNMENT); + prefixData += alignment; +#endif + + /* Set item data. */ + item->type = gcvBUFITEM_BUFFER; + item->indent = Indent; + item->bufferType = Type; + item->dataSize = DataSize; + item->address = Address; + item->prefixData = prefixData; + +#if gcdDMA_BUFFER_COUNT && (gcdTHREAD_BUFFERS == 1) + item->dmaAddress = DmaAddress; +#endif + + /* Copy prefix data. */ + memcpy(prefixData, PrefixData, gcdPREFIX_SIZE); + + /* Compute the data pointer. */ + data = prefixData + gcdPREFIX_SIZE; + + /* Copy argument value. */ + memcpy(data, Data, DataSize); + +#if gcdALIGNBYSIZE + /* Compute the actual node size. */ + size + = gcmSIZEOF(gcsBUFITEM_BUFFER) + + gcdPREFIX_SIZE + + alignment + + DataSize; + + /* Free extra memory if any. */ + freeSize = allocSize - size; + if (freeSize != 0) + { + _FreeExtraSpace(OutputBuffer, item, size, freeSize); + } +#endif +#else + gcsBUFITEM_BUFFER_PTR item; + gctINT size; + + gcmDBGASSERT(DataSize != 0, "%d", DataSize); + gcmDBGASSERT(Data != gcvNULL, "%p", Data); + + /* Determine the maximum item size. */ + size = gcmSIZEOF(gcsBUFITEM_BUFFER) + DataSize; + + /* Allocate prefix item. */ + item = (gcsBUFITEM_BUFFER_PTR) _AllocateItem(OutputBuffer, size); + + /* Set item data. */ + item->type = gcvBUFITEM_BUFFER; + item->indent = Indent; + item->dataSize = DataSize; + item->address = Address; + + /* Copy argument value. */ + memcpy(item + 1, Data, DataSize); +#endif +} +#endif + +static gcmINLINE void +_InitBuffers( + void + ) +{ + int i; + + if (_outputBufferHead == gcvNULL) + { + for (i = 0; i < gcdTHREAD_BUFFERS; i += 1) + { + if (_outputBufferTail == gcvNULL) + { + _outputBufferHead = &_outputBuffer[i]; + } + else + { + _outputBufferTail->next = &_outputBuffer[i]; + } + +#if gcdTHREAD_BUFFERS > 1 + _outputBuffer[i].threadID = ~0U; +#endif + + _outputBuffer[i].prev = _outputBufferTail; + _outputBuffer[i].next = gcvNULL; + + _outputBufferTail = &_outputBuffer[i]; + } + } +} + +static gcmINLINE gcsBUFFERED_OUTPUT_PTR +_GetOutputBuffer( + void + ) +{ + gcsBUFFERED_OUTPUT_PTR outputBuffer; + +#if gcdTHREAD_BUFFERS > 1 + /* Get the current thread ID. */ + gctUINT32 threadID = gcmkGETTHREADID(); + + /* Locate the output buffer for the thread. */ + outputBuffer = _outputBufferHead; + + while (outputBuffer != gcvNULL) + { + if (outputBuffer->threadID == ThreadID) + { + break; + } + + outputBuffer = outputBuffer->next; + } + + /* No matching buffer found? */ + if (outputBuffer == gcvNULL) + { + /* Get the tail for the buffer. */ + outputBuffer = _outputBufferTail; + + /* Move it to the head. */ + _outputBufferTail = _outputBufferTail->prev; + _outputBufferTail->next = gcvNULL; + + outputBuffer->prev = gcvNULL; + outputBuffer->next = _outputBufferHead; + + _outputBufferHead->prev = outputBuffer; + _outputBufferHead = outputBuffer; + + /* Reset the buffer. */ + outputBuffer->threadID = ThreadID; + outputBuffer->start = 0; + outputBuffer->index = 0; + outputBuffer->count = 0; + outputBuffer->lineNumber = 0; + } +#else + outputBuffer = _outputBufferHead; +#endif + + return outputBuffer; +} + +static gcmINLINE int _GetArgumentSize( + IN gctCONST_STRING Message + ) +{ + int i, count; + + gcmDBGASSERT(Message != gcvNULL, "%p", Message); + + for (i = 0, count = 0; Message[i]; i += 1) + { + if (Message[i] == '%') + { + count += 1; + } + } + + return count * gcmSIZEOF(gctUINT32); +} + +#if gcdHAVEPREFIX +static void +_InitPrefixData( + IN gcsBUFFERED_OUTPUT_PTR OutputBuffer, + IN gctPOINTER Data + ) +{ + gctUINT8_PTR data = (gctUINT8_PTR) Data; + +#if gcdSHOW_TIME + { + gctUINT64 time; + gckOS_GetProfileTick(&time); + gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64)); + * ((gctUINT64_PTR) data) = time; + data += gcmSIZEOF(gctUINT64); + } +#endif + +#if gcdSHOW_LINE_NUMBER + { + gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT64)); + * ((gctUINT64_PTR) data) = OutputBuffer->lineNumber; + data += gcmSIZEOF(gctUINT64); + } +#endif + +#if gcdSHOW_PROCESS_ID + { + gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32)); + * ((gctUINT32_PTR) data) = gcmkGETPROCESSID(); + data += gcmSIZEOF(gctUINT32); + } +#endif + +#if gcdSHOW_THREAD_ID + { + gcmkALIGNPTR(gctUINT8_PTR, data, gcmSIZEOF(gctUINT32)); + * ((gctUINT32_PTR) data) = gcmkGETTHREADID(); + } +#endif +} +#endif + +static void +_Print( + IN gctUINT ArgumentSize, + IN gctBOOL CopyMessage, + IN gctCONST_STRING Message, + IN gctARGUMENTS Arguments + ) +{ + gcsBUFFERED_OUTPUT_PTR outputBuffer; + gcmkDECLARE_LOCK(lockHandle); + + gcmkLOCKSECTION(lockHandle); + + /* Initialize output buffer list. */ + _InitBuffers(); + + /* Locate the proper output buffer. */ + outputBuffer = _GetOutputBuffer(); + + /* Update the line number. */ +#if gcdSHOW_LINE_NUMBER + outputBuffer->lineNumber += 1; +#endif + + /* Print prefix. */ +#if gcdHAVEPREFIX + { + gctUINT8_PTR alignedPrefixData; + gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT]; + + /* Compute aligned pointer. */ + alignedPrefixData = prefixData; + gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT); + + /* Initialize the prefix data. */ + _InitPrefixData(outputBuffer, alignedPrefixData); + + /* Print the prefix. */ + gcdOUTPUTPREFIX(outputBuffer, alignedPrefixData); + } +#endif + + /* Form the indent string. */ + if (strncmp(Message, "--", 2) == 0) + { + outputBuffer->indent -= 2; + } + + /* Print the message. */ + if (CopyMessage) + { + gcdOUTPUTCOPY( + outputBuffer, outputBuffer->indent, + Message, ArgumentSize, * (gctPOINTER *) &Arguments + ); + } + else + { + gcdOUTPUTSTRING( + outputBuffer, outputBuffer->indent, + Message, ArgumentSize, * (gctPOINTER *) &Arguments + ); + } + + /* Check increasing indent. */ + if (strncmp(Message, "++", 2) == 0) + { + outputBuffer->indent += 2; + } + + gcmkUNLOCKSECTION(lockHandle); +} + + +/******************************************************************************\ +********************************* Debug Macros ********************************* +\******************************************************************************/ + +#ifdef __QNXNTO__ + +extern volatile unsigned g_nQnxInIsrs; + +#define gcmDEBUGPRINT(ArgumentSize, CopyMessage, Message) \ +{ \ + if (atomic_add_value(&g_nQnxInIsrs, 1) == 0) \ + { \ + gctARGUMENTS __arguments__; \ + gcmkARGUMENTS_START(__arguments__, Message); \ + _Print(ArgumentSize, CopyMessage, Message, __arguments__); \ + gcmkARGUMENTS_END(__arguments__); \ + } \ + atomic_sub(&g_nQnxInIsrs, 1); \ +} + +#else + +#define gcmDEBUGPRINT(ArgumentSize, CopyMessage, Message) \ +{ \ + gctARGUMENTS __arguments__; \ + gcmkARGUMENTS_START(__arguments__, Message); \ + _Print(ArgumentSize, CopyMessage, Message, __arguments__); \ + gcmkARGUMENTS_END(__arguments__); \ +} + +#endif + +/******************************************************************************\ +********************************** Debug Code ********************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Print +** +** Send a message to the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ) +{ + gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_PrintN +** +** Send a message to the debugger. +** +** INPUT: +** +** gctUINT ArgumentSize +** The size of the optional arguments in bytes. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_PrintN( + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ) +{ + gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_CopyPrint +** +** Send a message to the debugger. If in buffered output mode, the entire +** message will be copied into the buffer instead of using the pointer to +** the string. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_CopyPrint( + IN gctCONST_STRING Message, + ... + ) +{ + gcmDEBUGPRINT(_GetArgumentSize(Message), gcvTRUE, Message); +} + +/******************************************************************************* +** +** gckOS_DumpBuffer +** +** Print the contents of the specified buffer. +** +** INPUT: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctPOINTER Buffer +** Pointer to the buffer to print. +** +** gctUINT Size +** Size of the buffer. +** +** gceDUMP_BUFFER Type +** Buffer type. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DumpBuffer( + IN gckOS Os, + IN gctPOINTER Buffer, + IN gctUINT Size, + IN gceDUMP_BUFFER Type, + IN gctBOOL CopyMessage + ) +{ + gctUINT32 address; + gcsBUFFERED_OUTPUT_PTR outputBuffer; + static gctBOOL userLocked; + gctCHAR *buffer = (gctCHAR*)Buffer; + + gcmkDECLARE_LOCK(lockHandle); + + /* Request lock when not coming from user, + or coming from user and not yet locked + and message is starting with @[. */ + if (Type == gceDUMP_BUFFER_FROM_USER) + { + if ((Size > 2) + && (buffer[0] == '@') + && (buffer[1] == '[')) + { + /* Beginning of a user dump. */ + gcmkLOCKSECTION(lockHandle); + userLocked = gcvTRUE; + } + /* Else, let it pass through. */ + } + else + { + gcmkLOCKSECTION(lockHandle); + userLocked = gcvFALSE; + } + + if (Buffer != gcvNULL) + { + /* Initialize output buffer list. */ + _InitBuffers(); + + /* Locate the proper output buffer. */ + outputBuffer = _GetOutputBuffer(); + + /* Update the line number. */ +#if gcdSHOW_LINE_NUMBER + outputBuffer->lineNumber += 1; +#endif + + /* Get the physical address of the buffer. */ + if (Type != gceDUMP_BUFFER_FROM_USER) + { + gcmkVERIFY_OK(gckOS_GetPhysicalAddress(Os, Buffer, &address)); + } + else + { + address = 0; + } + +#if gcdHAVEPREFIX + { + gctUINT8_PTR alignedPrefixData; + gctUINT8 prefixData[gcdPREFIX_SIZE + gcdPREFIX_ALIGNMENT]; + + /* Compute aligned pointer. */ + alignedPrefixData = prefixData; + gcmkALIGNPTR(gctUINT8_PTR, alignedPrefixData, gcdPREFIX_ALIGNMENT); + + /* Initialize the prefix data. */ + _InitPrefixData(outputBuffer, alignedPrefixData); + + /* Print/schedule the buffer. */ + gcdOUTPUTBUFFER( + outputBuffer, outputBuffer->indent, + alignedPrefixData, Buffer, address, Size, Type, 0 + ); + } +#else + /* Print/schedule the buffer. */ + if (Type == gceDUMP_BUFFER_FROM_USER) + { + gcdOUTPUTSTRING( + outputBuffer, outputBuffer->indent, + Buffer, 0, gcvNULL + ); + } + else + { + gcdOUTPUTBUFFER( + outputBuffer, outputBuffer->indent, + gcvNULL, Buffer, address, Size, Type, 0 + ); + } +#endif + } + + /* Unlock when not coming from user, + or coming from user and not yet locked. */ + if (userLocked) + { + if ((Size > 4) + && (buffer[0] == ']') + && (buffer[1] == ' ') + && (buffer[2] == '-') + && (buffer[3] == '-')) + { + /* End of a user dump. */ + gcmkUNLOCKSECTION(lockHandle); + userLocked = gcvFALSE; + } + /* Else, let it pass through, don't unlock. */ + } + else + { + gcmkUNLOCKSECTION(lockHandle); + } +} + +/******************************************************************************* +** +** gckOS_DebugTrace +** +** Send a leveled message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level of message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) +{ + if (Level > _debugLevel) + { + return; + } + + gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceN +** +** Send a leveled message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level of message. +** +** gctUINT ArgumentSize +** The size of the optional arguments in bytes. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceN( + IN gctUINT32 Level, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ) +{ + if (Level > _debugLevel) + { + return; + } + + gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceZone +** +** Send a leveled and zoned message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level for message. +** +** gctUINT32 Zone +** Debug zone for message. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) +{ + if ((Level > _debugLevel) || !(Zone & _debugZones)) + { + return; + } + + gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_DebugTraceZoneN +** +** Send a leveled and zoned message to the debugger. +** +** INPUT: +** +** gctUINT32 Level +** Debug level for message. +** +** gctUINT32 Zone +** Debug zone for message. +** +** gctUINT ArgumentSize +** The size of the optional arguments in bytes. +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugTraceZoneN( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ) +{ + if ((Level > _debugLevel) || !(Zone & _debugZones)) + { + return; + } + + gcmDEBUGPRINT(ArgumentSize, gcvFALSE, Message); +} + +/******************************************************************************* +** +** gckOS_DebugBreak +** +** Break into the debugger. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugBreak( + void + ) +{ + gckOS_DebugTrace(gcvLEVEL_ERROR, "%s(%d)", __FUNCTION__, __LINE__); +} + +/******************************************************************************* +** +** gckOS_DebugFatal +** +** Send a message to the debugger and break into the debugger. +** +** INPUT: +** +** gctCONST_STRING Message +** Pointer to message. +** +** ... +** Optional arguments. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ) +{ + gcmkPRINT_VERSION(); + gcmDEBUGPRINT(_GetArgumentSize(Message), gcvFALSE, Message); + + /* Break into the debugger. */ + gckOS_DebugBreak(); +} + +/******************************************************************************* +** +** gckOS_SetDebugLevel +** +** Set the debug level. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ) +{ + _debugLevel = Level; +} + +/******************************************************************************* +** +** gckOS_SetDebugZone +** +** Set the debug zone. +** +** INPUT: +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ) +{ + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugLevelZone +** +** Set the debug level and zone. +** +** INPUT: +** +** gctUINT32 Level +** New debug level. +** +** gctUINT32 Zone +** New debug zone. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ) +{ + _debugLevel = Level; + _debugZones = Zone; +} + +/******************************************************************************* +** +** gckOS_SetDebugZones +** +** Enable or disable debug zones. +** +** INPUT: +** +** gctUINT32 Zones +** Debug zones to enable or disable. +** +** gctBOOL Enable +** Set to gcvTRUE to enable the zones (or the Zones with the current +** zones) or gcvFALSE to disable the specified Zones. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ) +{ + if (Enable) + { + /* Enable the zones. */ + _debugZones |= Zones; + } + else + { + /* Disable the zones. */ + _debugZones &= ~Zones; + } +} + +/******************************************************************************* +** +** gckOS_Verify +** +** Called to verify the result of a function call. +** +** INPUT: +** +** gceSTATUS Status +** Function call result. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_Verify( + IN gceSTATUS Status + ) +{ + _lastError = Status; +} + +/******************************************************************************* +** +** gckOS_DebugFlush +** +** Force messages to be flushed out. +** +** INPUT: +** +** gctCONST_STRING CallerName +** Name of the caller function. +** +** gctUINT LineNumber +** Line number of the caller. +** +** gctUINT32 DmaAddress +** The current DMA address or ~0U to ignore. +** +** OUTPUT: +** +** Nothing. +*/ + +void +gckOS_DebugFlush( + gctCONST_STRING CallerName, + gctUINT LineNumber, + gctUINT32 DmaAddress + ) +{ +#if gcdBUFFERED_OUTPUT + _DirectPrint("\nFlush requested by %s(%d).\n\n", CallerName, LineNumber); + _Flush(DmaAddress); +#endif +} +gctCONST_STRING +gckOS_DebugStatus2Name( + gceSTATUS status + ) +{ + switch (status) + { + case gcvSTATUS_OK: + return "gcvSTATUS_OK"; + case gcvSTATUS_TRUE: + return "gcvSTATUS_TRUE"; + case gcvSTATUS_NO_MORE_DATA: + return "gcvSTATUS_NO_MORE_DATA"; + case gcvSTATUS_CACHED: + return "gcvSTATUS_CACHED"; + case gcvSTATUS_MIPMAP_TOO_LARGE: + return "gcvSTATUS_MIPMAP_TOO_LARGE"; + case gcvSTATUS_NAME_NOT_FOUND: + return "gcvSTATUS_NAME_NOT_FOUND"; + case gcvSTATUS_NOT_OUR_INTERRUPT: + return "gcvSTATUS_NOT_OUR_INTERRUPT"; + case gcvSTATUS_MISMATCH: + return "gcvSTATUS_MISMATCH"; + case gcvSTATUS_MIPMAP_TOO_SMALL: + return "gcvSTATUS_MIPMAP_TOO_SMALL"; + case gcvSTATUS_LARGER: + return "gcvSTATUS_LARGER"; + case gcvSTATUS_SMALLER: + return "gcvSTATUS_SMALLER"; + case gcvSTATUS_CHIP_NOT_READY: + return "gcvSTATUS_CHIP_NOT_READY"; + case gcvSTATUS_NEED_CONVERSION: + return "gcvSTATUS_NEED_CONVERSION"; + case gcvSTATUS_SKIP: + return "gcvSTATUS_SKIP"; + case gcvSTATUS_DATA_TOO_LARGE: + return "gcvSTATUS_DATA_TOO_LARGE"; + case gcvSTATUS_INVALID_CONFIG: + return "gcvSTATUS_INVALID_CONFIG"; + case gcvSTATUS_CHANGED: + return "gcvSTATUS_CHANGED"; + case gcvSTATUS_NOT_SUPPORT_DITHER: + return "gcvSTATUS_NOT_SUPPORT_DITHER"; + + case gcvSTATUS_INVALID_ARGUMENT: + return "gcvSTATUS_INVALID_ARGUMENT"; + case gcvSTATUS_INVALID_OBJECT: + return "gcvSTATUS_INVALID_OBJECT"; + case gcvSTATUS_OUT_OF_MEMORY: + return "gcvSTATUS_OUT_OF_MEMORY"; + case gcvSTATUS_MEMORY_LOCKED: + return "gcvSTATUS_MEMORY_LOCKED"; + case gcvSTATUS_MEMORY_UNLOCKED: + return "gcvSTATUS_MEMORY_UNLOCKED"; + case gcvSTATUS_HEAP_CORRUPTED: + return "gcvSTATUS_HEAP_CORRUPTED"; + case gcvSTATUS_GENERIC_IO: + return "gcvSTATUS_GENERIC_IO"; + case gcvSTATUS_INVALID_ADDRESS: + return "gcvSTATUS_INVALID_ADDRESS"; + case gcvSTATUS_CONTEXT_LOSSED: + return "gcvSTATUS_CONTEXT_LOSSED"; + case gcvSTATUS_TOO_COMPLEX: + return "gcvSTATUS_TOO_COMPLEX"; + case gcvSTATUS_BUFFER_TOO_SMALL: + return "gcvSTATUS_BUFFER_TOO_SMALL"; + case gcvSTATUS_INTERFACE_ERROR: + return "gcvSTATUS_INTERFACE_ERROR"; + case gcvSTATUS_NOT_SUPPORTED: + return "gcvSTATUS_NOT_SUPPORTED"; + case gcvSTATUS_MORE_DATA: + return "gcvSTATUS_MORE_DATA"; + case gcvSTATUS_TIMEOUT: + return "gcvSTATUS_TIMEOUT"; + case gcvSTATUS_OUT_OF_RESOURCES: + return "gcvSTATUS_OUT_OF_RESOURCES"; + case gcvSTATUS_INVALID_DATA: + return "gcvSTATUS_INVALID_DATA"; + case gcvSTATUS_INVALID_MIPMAP: + return "gcvSTATUS_INVALID_MIPMAP"; + case gcvSTATUS_NOT_FOUND: + return "gcvSTATUS_NOT_FOUND"; + case gcvSTATUS_NOT_ALIGNED: + return "gcvSTATUS_NOT_ALIGNED"; + case gcvSTATUS_INVALID_REQUEST: + return "gcvSTATUS_INVALID_REQUEST"; + case gcvSTATUS_GPU_NOT_RESPONDING: + return "gcvSTATUS_GPU_NOT_RESPONDING"; + case gcvSTATUS_TIMER_OVERFLOW: + return "gcvSTATUS_TIMER_OVERFLOW"; + case gcvSTATUS_VERSION_MISMATCH: + return "gcvSTATUS_VERSION_MISMATCH"; + case gcvSTATUS_LOCKED: + return "gcvSTATUS_LOCKED"; + + /* Linker errors. */ + case gcvSTATUS_GLOBAL_TYPE_MISMATCH: + return "gcvSTATUS_GLOBAL_TYPE_MISMATCH"; + case gcvSTATUS_TOO_MANY_ATTRIBUTES: + return "gcvSTATUS_TOO_MANY_ATTRIBUTES"; + case gcvSTATUS_TOO_MANY_UNIFORMS: + return "gcvSTATUS_TOO_MANY_UNIFORMS"; + case gcvSTATUS_TOO_MANY_VARYINGS: + return "gcvSTATUS_TOO_MANY_VARYINGS"; + case gcvSTATUS_UNDECLARED_VARYING: + return "gcvSTATUS_UNDECLARED_VARYING"; + case gcvSTATUS_VARYING_TYPE_MISMATCH: + return "gcvSTATUS_VARYING_TYPE_MISMATCH"; + case gcvSTATUS_MISSING_MAIN: + return "gcvSTATUS_MISSING_MAIN"; + case gcvSTATUS_NAME_MISMATCH: + return "gcvSTATUS_NAME_MISMATCH"; + case gcvSTATUS_INVALID_INDEX: + return "gcvSTATUS_INVALID_INDEX"; + default: + return "nil"; + } +} diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_event.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_event.c new file mode 100644 index 0000000..8b6fcf1 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_event.c @@ -0,0 +1,2678 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" +#include "gc_hal_kernel_buffer.h" + +#ifdef __QNXNTO__ +#include <atomic.h> +#include "gc_hal_kernel_qnx.h" +#endif + +#define _GC_OBJ_ZONE gcvZONE_EVENT + +#define gcdEVENT_ALLOCATION_COUNT (4096 / gcmSIZEOF(gcsHAL_INTERFACE)) +#define gcdEVENT_MIN_THRESHOLD 4 + +/******************************************************************************\ +********************************* Support Code ********************************* +\******************************************************************************/ + +static gceSTATUS +gckEVENT_AllocateQueue( + IN gckEVENT Event, + OUT gcsEVENT_QUEUE_PTR * Queue + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Queue != gcvNULL); + + /* Do we have free queues? */ + if (Event->freeList == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Move one free queue from the free list. */ + * Queue = Event->freeList; + Event->freeList = Event->freeList->next; + + /* Success. */ + gcmkFOOTER_ARG("*Queue=0x%x", gcmOPT_POINTER(Queue)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +gckEVENT_FreeQueue( + IN gckEVENT Event, + OUT gcsEVENT_QUEUE_PTR Queue + ) +{ + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Queue != gcvNULL); + + /* Move one free queue from the free list. */ + Queue->next = Event->freeList; + Event->freeList = Queue; + + /* Success. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +gckEVENT_FreeRecord( + IN gckEVENT Event, + IN gcsEVENT_PTR Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->freeEventMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Push the record on the free list. */ + Record->next = Event->freeEventList; + Event->freeEventList = Record; + Event->freeEventCount += 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return gcvSTATUS_OK; +} + +#ifndef __QNXNTO__ + +static gceSTATUS +gckEVENT_IsEmpty( + IN gckEVENT Event, + OUT gctBOOL_PTR IsEmpty + ) +{ + gceSTATUS status; + gctSIZE_T i; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(IsEmpty != gcvNULL); + + /* Assume the event queue is empty. */ + *IsEmpty = gcvTRUE; + + /* Walk the event queue. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + /* Check whether this event is in use. */ + if (Event->queues[i].head != gcvNULL) + { + /* The event is in use, hence the queue is not empty. */ + *IsEmpty = gcvFALSE; + break; + } + } + + /* Try acquiring the mutex. */ + status = gckOS_AcquireMutex(Event->os, Event->eventQueueMutex, 0); + if (status == gcvSTATUS_TIMEOUT) + { + /* Timeout - queue is no longer empty. */ + *IsEmpty = gcvFALSE; + } + else + { + /* Bail out on error. */ + gcmkONERROR(status); + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + } + + /* Success. */ + gcmkFOOTER_ARG("*IsEmpty=%d", gcmOPT_VALUE(IsEmpty)); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#endif + +static gceSTATUS +_TryToIdleGPU( + IN gckEVENT Event +) +{ +#ifndef __QNXNTO__ + gceSTATUS status; + gctBOOL empty = gcvFALSE, idle = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Check whether the event queue is empty. */ + gcmkONERROR(gckEVENT_IsEmpty(Event, &empty)); + + if (empty) + { + /* Query whether the hardware is idle. */ + gcmkONERROR(gckHARDWARE_QueryIdle(Event->kernel->hardware, &idle)); + + if (idle) + { + /* Inform the system of idle GPU. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_IDLE)); + } + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +#else + return gcvSTATUS_OK; +#endif +} + +static gceSTATUS +__RemoveRecordFromProcessDB( + IN gckEVENT Event, + IN gcsEVENT_PTR Record + ) +{ + gcmkHEADER_ARG("Event=0x%x Record=0x%x", Event, Record); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + while (Record != gcvNULL) + { + switch (Record->info.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Event->kernel, + Record->processID, + gcvDB_NON_PAGED, + Record->info.u.FreeNonPagedMemory.logical)); + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Event->kernel, + Record->processID, + gcvDB_CONTIGUOUS, + Record->info.u.FreeContiguousMemory.logical)); + break; + + case gcvHAL_FREE_VIDEO_MEMORY: + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Event->kernel, + Record->processID, + gcvDB_VIDEO_MEMORY, + Record->info.u.FreeVideoMemory.node)); + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Event->kernel, + Record->processID, + gcvDB_VIDEO_MEMORY_LOCKED, + Record->info.u.UnlockVideoMemory.node)); + break; + + default: + break; + } + + Record = Record->next; + } + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************\ +******************************* gckEVENT API Code ******************************* +\******************************************************************************/ + +/******************************************************************************* +** +** gckEVENT_Construct +** +** Construct a new gckEVENT object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gckEVENT * Event +** Pointer to a variable that receives the gckEVENT object pointer. +*/ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ) +{ + gckOS os; + gceSTATUS status; + gckEVENT eventObj = gcvNULL; + int i; + gcsEVENT_PTR record; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Event != gcvNULL); + + /* Extract the pointer to the gckOS object. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate the gckEVENT object. */ + gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(struct _gckEVENT), &pointer)); + + eventObj = pointer; + + /* Reset the object. */ + gcmkVERIFY_OK(gckOS_ZeroMemory(eventObj, gcmSIZEOF(struct _gckEVENT))); + + /* Initialize the gckEVENT object. */ + eventObj->object.type = gcvOBJ_EVENT; + eventObj->kernel = Kernel; + eventObj->os = os; + + /* Create the mutexes. */ + gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventQueueMutex)); + gcmkONERROR(gckOS_CreateMutex(os, &eventObj->freeEventMutex)); + gcmkONERROR(gckOS_CreateMutex(os, &eventObj->eventListMutex)); + + /* Create a bunch of event reccords. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1) + { + /* Allocate an event record. */ + gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcsEVENT), &pointer)); + + record = pointer; + + /* Push it on the free list. */ + record->next = eventObj->freeEventList; + eventObj->freeEventList = record; + eventObj->freeEventCount += 1; + } + + /* Initialize the free list of event queues. */ + for (i = 0; i < gcdREPO_LIST_COUNT; i += 1) + { + eventObj->repoList[i].next = eventObj->freeList; + eventObj->freeList = &eventObj->repoList[i]; + } + + /* Construct the atom. */ + gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->freeAtom)); + gcmkONERROR(gckOS_AtomSet(os, + eventObj->freeAtom, + gcmCOUNTOF(eventObj->queues))); + +#if gcdSMP + gcmkONERROR(gckOS_AtomConstruct(os, &eventObj->pending)); +#endif + + /* Return pointer to the gckEVENT object. */ + *Event = eventObj; + + /* Success. */ + gcmkFOOTER_ARG("*Event=0x%x", *Event); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (eventObj != gcvNULL) + { + if (eventObj->eventQueueMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventQueueMutex)); + } + + if (eventObj->freeEventMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->freeEventMutex)); + } + + if (eventObj->eventListMutex != gcvNULL) + { + gcmkVERIFY_OK(gckOS_DeleteMutex(os, eventObj->eventListMutex)); + } + + while (eventObj->freeEventList != gcvNULL) + { + record = eventObj->freeEventList; + eventObj->freeEventList = record->next; + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, record)); + } + + if (eventObj->freeAtom != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->freeAtom)); + } + +#if gcdSMP + if (eventObj->pending != gcvNULL) + { + gcmkVERIFY_OK(gckOS_AtomDestroy(os, eventObj->pending)); + } +#endif + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, eventObj)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Destroy +** +** Destroy an gckEVENT object. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ) +{ + gcsEVENT_PTR record; + gcsEVENT_QUEUE_PTR queue; + + gcmkHEADER_ARG("Event=0x%x", Event); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Delete the queue mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventQueueMutex)); + + /* Free all free events. */ + while (Event->freeEventList != gcvNULL) + { + record = Event->freeEventList; + Event->freeEventList = record->next; + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record)); + } + + /* Delete the free mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->freeEventMutex)); + + /* Free all pending queues. */ + while (Event->queueHead != gcvNULL) + { + /* Get the current queue. */ + queue = Event->queueHead; + + /* Free all pending events. */ + while (queue->head != gcvNULL) + { + record = queue->head; + queue->head = record->next; + + gcmkTRACE_ZONE_N( + gcvLEVEL_WARNING, gcvZONE_EVENT, + gcmSIZEOF(record) + gcmSIZEOF(queue->source), + "Event record 0x%x is still pending for %d.", + record, queue->source + ); + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, record)); + } + + /* Remove the top queue from the list. */ + if (Event->queueHead == Event->queueTail) + { + Event->queueHead = + Event->queueTail = gcvNULL; + } + else + { + Event->queueHead = Event->queueHead->next; + } + + /* Free the queue. */ + gcmkVERIFY_OK(gckEVENT_FreeQueue(Event, queue)); + } + + /* Delete the list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Event->os, Event->eventListMutex)); + + /* Delete the atom. */ + gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->freeAtom)); + +#if gcdSMP + gcmkVERIFY_OK(gckOS_AtomDestroy(Event->os, Event->pending)); +#endif + /* Mark the gckEVENT object as unknown. */ + Event->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckEVENT object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Event->os, Event)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckEVENT_GetEvent +** +** Reserve the next available hardware event. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctBOOL Wait +** Set to gcvTRUE to force the function to wait if no events are +** immediately available. +** +** gceKERNEL_WHERE Source +** Source of the event. +** +** OUTPUT: +** +** gctUINT8 * EventID +** Reserved event ID. +*/ +gceSTATUS +gckEVENT_GetEvent( + IN gckEVENT Event, + IN gctBOOL Wait, + OUT gctUINT8 * EventID, + IN gceKERNEL_WHERE Source + ) +{ + gctINT i, id; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctINT32 free; + +#if gcdGPU_TIMEOUT + gctUINT32 timer = 0; +#endif + + gcmkHEADER_ARG("Event=0x%x Source=%d", Event, Source); + + while (gcvTRUE) + { + /* Grab the queue mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->eventQueueMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Walk through all events. */ + id = Event->lastID; + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + gctINT nextID = gckMATH_ModuloInt((id + 1), + gcmCOUNTOF(Event->queues)); + + if (Event->queues[id].head == gcvNULL) + { + *EventID = (gctUINT8) id; + + Event->lastID = (gctUINT8) nextID; + + /* Save time stamp of event. */ + Event->queues[id].stamp = ++(Event->stamp); + Event->queues[id].source = Source; + + gcmkONERROR(gckOS_AtomDecrement(Event->os, + Event->freeAtom, + &free)); +#if gcdDYNAMIC_SPEED + if (free <= gcdDYNAMIC_EVENT_THRESHOLD) + { + gcmkONERROR(gckOS_BroadcastHurry( + Event->os, + Event->kernel->hardware, + gcdDYNAMIC_EVENT_THRESHOLD - free)); + } +#endif + + /* Release the queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, + Event->eventQueueMutex)); + + /* Success. */ + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_EVENT, + gcmSIZEOF(id), + "Using id=%d", + id + ); + + gcmkFOOTER_ARG("*EventID=%u", *EventID); + return gcvSTATUS_OK; + } + + id = nextID; + } + +#if gcdDYNAMIC_SPEED + /* No free events, speed up the GPU right now! */ + gcmkONERROR(gckOS_BroadcastHurry(Event->os, + Event->kernel->hardware, + gcdDYNAMIC_EVENT_THRESHOLD)); +#endif + + /* Release the queue mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + acquired = gcvFALSE; + + /* Fail if wait is not requested. */ + if (!Wait) + { + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Delay a while. */ + gcmkONERROR(gckOS_Delay(Event->os, 1)); + +#if gcdGPU_TIMEOUT + /* Increment the wait timer. */ + timer += 1; + + if (timer == gcdGPU_TIMEOUT) + { + /* Try to call any outstanding events. */ + gcmkONERROR(gckHARDWARE_Interrupt(Event->kernel->hardware, + gcvTRUE)); + } + else if (timer > gcdGPU_TIMEOUT) + { + gcmkTRACE_N( + gcvLEVEL_ERROR, + gcmSIZEOF(gctCONST_STRING) + gcmSIZEOF(gctINT), + "%s(%d): no available events\n", + __FUNCTION__, __LINE__ + ); + + /* Broadcast GPU stuck. */ + gcmkONERROR(gckOS_Broadcast(Event->os, + Event->kernel->hardware, + gcvBROADCAST_GPU_STUCK)); + + /* Bail out. */ + gcmkONERROR(gcvSTATUS_GPU_NOT_RESPONDING); + } +#endif + } + +OnError: + if (acquired) + { + /* Release the queue mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_AllocateRecord +** +** Allocate a record for the new event. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctBOOL AllocateAllowed +** State for allocation if out of free events. +** +** OUTPUT: +** +** gcsEVENT_PTR * Record +** Allocated event record. +*/ +gceSTATUS +gckEVENT_AllocateRecord( + IN gckEVENT Event, + IN gctBOOL AllocateAllowed, + OUT gcsEVENT_PTR * Record + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctINT i; + gcsEVENT_PTR record; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Event=0x%x AllocateAllowed=%d", Event, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Record != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->freeEventMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Test if we are below the allocation threshold. */ + if ( (AllocateAllowed && (Event->freeEventCount < gcdEVENT_MIN_THRESHOLD)) || + (Event->freeEventCount == 0) ) + { + /* Allocate a bunch of records. */ + for (i = 0; i < gcdEVENT_ALLOCATION_COUNT; i += 1) + { + /* Allocate an event record. */ + gcmkONERROR(gckOS_Allocate(Event->os, + gcmSIZEOF(gcsEVENT), + &pointer)); + + record = pointer; + + /* Push it on the free list. */ + record->next = Event->freeEventList; + Event->freeEventList = record; + Event->freeEventCount += 1; + } + } + + *Record = Event->freeEventList; + Event->freeEventList = Event->freeEventList->next; + Event->freeEventCount -= 1; + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); + acquired = gcvFALSE; + + /* Success. */ + gcmkFOOTER_ARG("*Record=0x%x", gcmOPT_POINTER(Record)); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->freeEventMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_AddList +** +** Add a new event to the list of events. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcsHAL_INTERFACE_PTR Interface +** Pointer to the interface for the event to be added. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** gctBOOL AllocateAllowed +** State for allocation if out of free events. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_AddList( + IN gckEVENT Event, + IN gcsHAL_INTERFACE_PTR Interface, + IN gceKERNEL_WHERE FromWhere, + IN gctBOOL AllocateAllowed + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcsEVENT_PTR record = gcvNULL; + gcsEVENT_QUEUE_PTR queue; + + gcmkHEADER_ARG("Event=0x%x Interface=0x%x", + Event, Interface); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, _GC_OBJ_ZONE, + "FromWhere=%d AllocateAllowed=%d", + FromWhere, AllocateAllowed); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Interface != gcvNULL); + + /* Verify the event command. */ + gcmkASSERT + ( (Interface->command == gcvHAL_FREE_NON_PAGED_MEMORY) + || (Interface->command == gcvHAL_FREE_CONTIGUOUS_MEMORY) + || (Interface->command == gcvHAL_FREE_VIDEO_MEMORY) + || (Interface->command == gcvHAL_WRITE_DATA) + || (Interface->command == gcvHAL_UNLOCK_VIDEO_MEMORY) + || (Interface->command == gcvHAL_SIGNAL) + || (Interface->command == gcvHAL_UNMAP_USER_MEMORY) + || (Interface->command == gcvHAL_TIMESTAMP) + || (Interface->command == gcvHAL_COMMIT_DONE) + ); + + /* Validate the source. */ + if ((FromWhere != gcvKERNEL_COMMAND) && (FromWhere != gcvKERNEL_PIXEL)) + { + /* Invalid argument. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Allocate a free record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, AllocateAllowed, &record)); + + /* Termninate the record. */ + record->next = gcvNULL; + + /* Copy the event interface into the record. */ + gcmkONERROR(gckOS_MemCopy(&record->info, Interface, gcmSIZEOF(record->info))); + + /* Get process ID. */ + gcmkONERROR(gckOS_GetProcessID(&record->processID)); + +#ifdef __QNXNTO__ + record->kernel = Event->kernel; +#endif + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, Event->eventListMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Do we need to allocate a new queue? */ + if ((Event->queueTail == gcvNULL) || (Event->queueTail->source != FromWhere)) + { + /* Allocate a new queue. */ + gcmkONERROR(gckEVENT_AllocateQueue(Event, &queue)); + + /* Initialize the queue. */ + queue->source = FromWhere; + queue->head = gcvNULL; + queue->next = gcvNULL; + + /* Attach it to the list of allocated queues. */ + if (Event->queueTail == gcvNULL) + { + Event->queueHead = + Event->queueTail = queue; + } + else + { + Event->queueTail->next = queue; + Event->queueTail = queue; + } + } + else + { + queue = Event->queueTail; + } + + /* Attach the record to the queue. */ + if (queue->head == gcvNULL) + { + queue->head = record; + queue->tail = record; + } + else + { + queue->tail->next = record; + queue->tail = record; + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); + } + + if (record != gcvNULL) + { + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Unlock +** +** Schedule an event to unlock virtual memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union that specifies the virtual memory +** to unlock. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x FromWhere=%d Node=0x%x Type=%d", + Event, FromWhere, Node, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + + /* Mark the event as an unlock. */ + iface.command = gcvHAL_UNLOCK_VIDEO_MEMORY; + iface.u.UnlockVideoMemory.node = Node; + iface.u.UnlockVideoMemory.type = Type; + iface.u.UnlockVideoMemory.asynchroneous = 0; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeVideoMemory +** +** Schedule an event to free video memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcuVIDMEM_NODE_PTR VideoMemory +** Pointer to a gcuVIDMEM_NODE object to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x VideoMemory=0x%x FromWhere=%d", + Event, VideoMemory, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(VideoMemory != gcvNULL); + + /* Create an event. */ + iface.command = gcvHAL_FREE_VIDEO_MEMORY; + iface.u.FreeVideoMemory.node = VideoMemory; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeNonPagedMemory +** +** Schedule an event to free non-paged memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of non-paged memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of non-paged memory to free. +** +** gctPOINTER Logical +** Logical address of non-paged memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_NON_PAGED_MEMORY; + iface.u.FreeNonPagedMemory.bytes = Bytes; + iface.u.FreeNonPagedMemory.physical = Physical; + iface.u.FreeNonPagedMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_FreeContigiuousMemory +** +** Schedule an event to free contiguous memory. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIZE_T Bytes +** Number of bytes of contiguous memory to free. +** +** gctPHYS_ADDR Physical +** Physical address of contiguous memory to free. +** +** gctPOINTER Logical +** Logical address of contiguous memory to free. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +*/ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Bytes=%lu Physical=0x%x Logical=0x%x " + "FromWhere=%d", + Event, Bytes, Physical, Logical, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Create an event. */ + iface.command = gcvHAL_FREE_CONTIGUOUS_MEMORY; + iface.u.FreeContiguousMemory.bytes = Bytes; + iface.u.FreeContiguousMemory.physical = Physical; + iface.u.FreeContiguousMemory.logical = Logical; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Signal +** +** Schedule an event to trigger a signal. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctSIGNAL Signal +** Pointer to the signal to trigger. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x Signal=0x%x FromWhere=%d", + Event, Signal, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + /* Mark the event as a signal. */ + iface.command = gcvHAL_SIGNAL; + iface.u.Signal.signal = Signal; +#ifdef __QNXNTO__ + iface.u.Signal.coid = 0; + iface.u.Signal.rcvid = 0; +#endif + iface.u.Signal.auxSignal = gcvNULL; + iface.u.Signal.process = gcvNULL; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_CommitDone +** +** Schedule an event to wake up work thread when commit is done by GPU. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gceKERNEL_WHERE FromWhere +** Place in the pipe where the event needs to be generated. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_CommitDone( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE iface; + + gcmkHEADER_ARG("Event=0x%x FromWhere=%d", Event, FromWhere); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + iface.command = gcvHAL_COMMIT_DONE; + + /* Append it to the queue. */ + gcmkONERROR(gckEVENT_AddList(Event, &iface, FromWhere, gcvFALSE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +/******************************************************************************* +** +** gckEVENT_Submit +** +** Submit the current event queue to the GPU. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctBOOL Wait +** Submit requires one vacant event; if Wait is set to not zero, +** and there are no vacant events at this time, the function will +** wait until an event becomes vacant so that submission of the +** queue is successful. +** +** gctBOOL FromPower +** Determines whether the call originates from inside the power +** management or not. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait, + IN gctBOOL FromPower + ) +{ + gceSTATUS status; + gctUINT8 id = 0xFF; + gcsEVENT_QUEUE_PTR queue; + gctBOOL acquired = gcvFALSE; + gckCOMMAND command = gcvNULL; + gctBOOL commitEntered = gcvFALSE; +#if !gcdNULL_DRIVER + gctSIZE_T bytes; + gctPOINTER buffer; +#endif + + gcmkHEADER_ARG("Event=0x%x Wait=%d", Event, Wait); + + /* Get gckCOMMAND object. */ + command = Event->kernel->command; + + /* Are there event queues? */ + if (Event->queueHead != gcvNULL) + { + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(command, FromPower)); + commitEntered = gcvTRUE; + + /* Process all queues. */ + while (Event->queueHead != gcvNULL) + { + /* Acquire the list mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->eventListMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Get the current queue. */ + queue = Event->queueHead; + + /* Allocate an event ID. */ + gcmkONERROR(gckEVENT_GetEvent(Event, Wait, &id, queue->source)); + + /* Copy event list to event ID queue. */ + Event->queues[id].source = queue->source; + Event->queues[id].head = queue->head; + + /* Remove the top queue from the list. */ + if (Event->queueHead == Event->queueTail) + { + Event->queueHead = gcvNULL; + Event->queueTail = gcvNULL; + } + else + { + Event->queueHead = Event->queueHead->next; + } + + /* Free the queue. */ + gcmkONERROR(gckEVENT_FreeQueue(Event, queue)); + + /* Release the list mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); + acquired = gcvFALSE; + + gcmkONERROR(__RemoveRecordFromProcessDB(Event, + Event->queues[id].head)); + +#if gcdNULL_DRIVER + /* Notify immediately on infinite hardware. */ + gcmkONERROR(gckEVENT_Interrupt(Event, 1 << id)); + + gcmkONERROR(gckEVENT_Notify(Event, 0)); +#else + /* Get the size of the hardware event. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + gcvNULL, + id, + gcvKERNEL_PIXEL, + &bytes)); + + /* Reserve space in the command queue. */ + gcmkONERROR(gckCOMMAND_Reserve(command, + bytes, + &buffer, + &bytes)); + + /* Set the hardware event in the command queue. */ + gcmkONERROR(gckHARDWARE_Event(Event->kernel->hardware, + buffer, + id, + Event->queues[id].source, + &bytes)); + + /* Execute the hardware event. */ + gcmkONERROR(gckCOMMAND_Execute(command, bytes)); +#endif + } + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(command, FromPower)); + commitEntered = gcvFALSE; + +#if !gcdNULL_DRIVER + gcmkVERIFY_OK(_TryToIdleGPU(Event)); +#endif + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, FromPower)); + } + + if (acquired) + { + /* Need to unroll the mutex acquire. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventListMutex)); + } + + if (id != 0xFF) + { + /* Need to unroll the event allocation. */ + Event->queues[id].head = gcvNULL; + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Commit +** +** Commit an event queue from the user. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcsQUEUE_PTR Queue +** User event queue. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN gcsQUEUE_PTR Queue + ) +{ + gceSTATUS status; + gcsQUEUE_PTR record = gcvNULL, next; + gctUINT32 processID; + gctBOOL needCopy = gcvFALSE; + + gcmkHEADER_ARG("Event=0x%x Queue=0x%x", Event, Queue); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Get the current process ID. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + + /* Query if we need to copy the client data. */ + gcmkONERROR(gckOS_QueryNeedCopy(Event->os, processID, &needCopy)); + + /* Loop while there are records in the queue. */ + while (Queue != gcvNULL) + { + gcsQUEUE queue; + + if (needCopy) + { + /* Point to stack record. */ + record = &queue; + + /* Copy the data from the client. */ + gcmkONERROR(gckOS_CopyFromUserData(Event->os, + record, + Queue, + gcmSIZEOF(gcsQUEUE))); + } + else + { + gctPOINTER pointer = gcvNULL; + + /* Map record into kernel memory. */ + gcmkONERROR(gckOS_MapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + &pointer)); + + record = pointer; + } + + /* Append event record to event queue. */ + gcmkONERROR( + gckEVENT_AddList(Event, &record->iface, gcvKERNEL_PIXEL, gcvTRUE)); + + /* Next record in the queue. */ + next = record->next; + + if (!needCopy) + { + /* Unmap record from kernel memory. */ + gcmkONERROR( + gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + record = gcvNULL; + } + + Queue = next; + } + + /* Submit the event list. */ + gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE)); + + /* Success */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if ((record != gcvNULL) && !needCopy) + { + /* Roll back. */ + gcmkVERIFY_OK(gckOS_UnmapUserPointer(Event->os, + Queue, + gcmSIZEOF(gcsQUEUE), + (gctPOINTER *) record)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Compose +** +** Schedule a composition event and start a composition. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gcsHAL_COMPOSE_PTR Info +** Pointer to the composition structure. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Compose( + IN gckEVENT Event, + IN gcsHAL_COMPOSE_PTR Info + ) +{ + gceSTATUS status; + gcsEVENT_PTR headRecord; + gcsEVENT_PTR tailRecord; + gcsEVENT_PTR tempRecord; + gctUINT8 id = 0xFF; + gctUINT32 processID; + + gcmkHEADER_ARG("Event=0x%x Info=0x%x", Event, Info); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + /* Allocate an event ID. */ + gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL)); + + /* Get process ID. */ + gcmkONERROR(gckOS_GetProcessID(&processID)); + + /* Allocate a record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); + headRecord = tailRecord = tempRecord; + + /* Initialize the record. */ + tempRecord->info.command = gcvHAL_SIGNAL; + tempRecord->info.u.Signal.process = Info->process; +#ifdef __QNXNTO__ + tempRecord->info.u.Signal.coid = Info->coid; + tempRecord->info.u.Signal.rcvid = Info->rcvid; +#endif + tempRecord->info.u.Signal.signal = Info->signal; + tempRecord->info.u.Signal.auxSignal = gcvNULL; + tempRecord->next = gcvNULL; + tempRecord->processID = processID; + + /* Allocate another record for user signal #1. */ + if (Info->userSignal1 != gcvNULL) + { + /* Allocate a record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); + tailRecord->next = tempRecord; + tailRecord = tempRecord; + + /* Initialize the record. */ + tempRecord->info.command = gcvHAL_SIGNAL; + tempRecord->info.u.Signal.process = Info->userProcess; +#ifdef __QNXNTO__ + tempRecord->info.u.Signal.coid = Info->coid; + tempRecord->info.u.Signal.rcvid = Info->rcvid; +#endif + tempRecord->info.u.Signal.signal = Info->userSignal1; + tempRecord->info.u.Signal.auxSignal = gcvNULL; + tempRecord->next = gcvNULL; + tempRecord->processID = processID; + } + + /* Allocate another record for user signal #2. */ + if (Info->userSignal2 != gcvNULL) + { + /* Allocate a record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &tempRecord)); + tailRecord->next = tempRecord; + tailRecord = tempRecord; + + /* Initialize the record. */ + tempRecord->info.command = gcvHAL_SIGNAL; + tempRecord->info.u.Signal.process = Info->userProcess; +#ifdef __QNXNTO__ + tempRecord->info.u.Signal.coid = Info->coid; + tempRecord->info.u.Signal.rcvid = Info->rcvid; +#endif + tempRecord->info.u.Signal.signal = Info->userSignal2; + tempRecord->info.u.Signal.auxSignal = gcvNULL; + tempRecord->next = gcvNULL; + tempRecord->processID = processID; + } + + /* Set the event list. */ + Event->queues[id].head = headRecord; + + /* Start composition. */ + gcmkONERROR(gckHARDWARE_Compose( + Event->kernel->hardware, processID, + Info->physical, Info->logical, Info->offset, Info->size, id + )); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckEVENT_Interrupt +** +** Called by the interrupt service routine to store the triggered interrupt +** mask to be later processed by gckEVENT_Notify. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctUINT32 Data +** Mask for the 32 interrupts. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 Data + ) +{ + gcmkHEADER_ARG("Event=0x%x Data=0x%x", Event, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Combine current interrupt status with pending flags. */ +#if gcdSMP + gckOS_AtomSetMask(Event->pending, Data); +#elif defined(__QNXNTO__) + atomic_set(&Event->pending, Data); +#else + Event->pending |= Data; +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckEVENT_Notify +** +** Process all triggered interrupts. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gctINT i; + gcsEVENT_QUEUE * queue; + gctUINT mask = 0; + gctBOOL acquired = gcvFALSE; +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node; +#endif + gctUINT pending; + gctBOOL suspended = gcvFALSE; +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gctINT eventNumber = 0; +#endif + gctINT32 free; +#if gcdSECURE_USER + gcskSECURE_CACHE_PTR cache; +#endif + + gcmkHEADER_ARG("Event=0x%x IDs=0x%x", Event, IDs); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + gcmDEBUG_ONLY( + if (IDs != 0) + { + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[i].head != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Queue(%d): stamp=%llu source=%d", + i, + Event->queues[i].stamp, + Event->queues[i].source); + } + } + } + ); + + for (;;) + { + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvTRUE; + + /* Get current interrupts. */ +#if gcdSMP + gckOS_AtomGet(Event->os, Event->pending, (gctINT32_PTR)&pending); +#else + pending = Event->pending; +#endif + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvFALSE; + + if (pending == 0) + { + /* No more pending interrupts - done. */ + break; + } + + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_EVENT, + gcmSIZEOF(pending), + "Pending interrupts 0x%x", + pending + ); + + queue = gcvNULL; + + gcmDEBUG_ONLY( + if (IDs == 0) + { + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[i].head != gcvNULL) + { + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Queue(%d): stamp=%llu source=%d", + i, + Event->queues[i].stamp, + Event->queues[i].source); + } + } + } + ); + + /* Find the oldest pending interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (pending & (1 << i)) + ) + { + if ((queue == gcvNULL) + || (Event->queues[i].stamp < queue->stamp) + ) + { + queue = &Event->queues[i]; + mask = 1 << i; +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + eventNumber = i; +#endif + } + } + } + + if (queue == gcvNULL) + { + gcmkTRACE_ZONE_N( + gcvLEVEL_ERROR, gcvZONE_EVENT, + gcmSIZEOF(pending), + "Interrupts 0x%x are not pending.", + pending + ); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvTRUE; + + /* Mark pending interrupts as handled. */ +#if gcdSMP + gckOS_AtomClearMask(Event->pending, pending); +#elif defined(__QNXNTO__) + atomic_clr((gctUINT32_PTR)&Event->pending, pending); +#else + Event->pending &= ~pending; +#endif + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvFALSE; + + break; + } + + /* Check whether there is a missed interrupt. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if ((Event->queues[i].head != gcvNULL) + && (Event->queues[i].stamp < queue->stamp) + && (Event->queues[i].source == queue->source) + ) + { + gcmkTRACE_N( + gcvLEVEL_ERROR, + gcmSIZEOF(i) + gcmSIZEOF(Event->queues[i].stamp), + "Event %d lost (stamp %llu)", + i, Event->queues[i].stamp + ); + + /* Use this event instead. */ + queue = &Event->queues[i]; + mask = 0; + } + } + + if (mask != 0) + { +#if gcmIS_DEBUG(gcdDEBUG_TRACE) + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_EVENT, + gcmSIZEOF(eventNumber), + "Processing interrupt %d", + eventNumber + ); +#endif + } + + /* Walk all events for this interrupt. */ + for (;;) + { + gcsEVENT_PTR record; + gcsEVENT_PTR recordNext = gcvNULL; +#ifndef __QNXNTO__ + gctPOINTER logical; +#endif +#if gcdSECURE_USER + gctSIZE_T bytes; +#endif + + /* Grab the mutex queue. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->eventQueueMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Grab the event head. */ + record = queue->head; + + if (record != gcvNULL) + { + queue->head = record->next; + recordNext = record->next; + } + + /* Release the mutex queue. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + acquired = gcvFALSE; + + /* Dispatch on event type. */ + if (record != gcvNULL) + { +#ifdef __QNXNTO__ + /* Assign record->processID as the pid for this galcore thread. + * Used in OS calls like gckOS_UnlockMemory() which do not take a pid. + */ + drv_thread_specific_key_assign(record->processID, 0); +#endif + +#if gcdSECURE_USER + /* Get the cache that belongs to this process. */ + gcmkONERROR(gckKERNEL_GetProcessDBCache(Event->kernel, + record->processID, + &cache)); +#endif + + gcmkTRACE_ZONE_N( + gcvLEVEL_INFO, gcvZONE_EVENT, + gcmSIZEOF(record->info.command), + "Processing event type: %d", + record->info.command + ); + + switch (record->info.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_FREE_NON_PAGED_MEMORY: 0x%x", + record->info.u.FreeNonPagedMemory.physical); + + /* Free non-paged memory. */ + status = gckOS_FreeNonPagedMemory( + Event->os, + record->info.u.FreeNonPagedMemory.bytes, + record->info.u.FreeNonPagedMemory.physical, + record->info.u.FreeNonPagedMemory.logical); + + if (gcmIS_SUCCESS(status)) + { +#if gcdSECURE_USER + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Event->kernel, + cache, + record->event.u.FreeNonPagedMemory.logical, + record->event.u.FreeNonPagedMemory.bytes)); +#endif + } + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_FREE_CONTIGUOUS_MEMORY: 0x%x", + record->info.u.FreeContiguousMemory.physical); + + /* Unmap the user memory. */ + status = gckOS_FreeContiguous( + Event->os, + record->info.u.FreeContiguousMemory.physical, + record->info.u.FreeContiguousMemory.logical, + record->info.u.FreeContiguousMemory.bytes); + + if (gcmIS_SUCCESS(status)) + { +#if gcdSECURE_USER + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Event->kernel, + cache, + event->event.u.FreeContiguousMemory.logical, + event->event.u.FreeContiguousMemory.bytes)); +#endif + } + break; + + case gcvHAL_FREE_VIDEO_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_FREE_VIDEO_MEMORY: 0x%x", + record->info.u.FreeVideoMemory.node); + +#ifdef __QNXNTO__ + node = record->info.u.FreeVideoMemory.node; +#if gcdUSE_VIDMEM_PER_PID + /* Check if the VidMem object still exists. */ + if (gckKERNEL_GetVideoMemoryPoolPid(record->kernel, + gcvPOOL_SYSTEM, + record->processID, + gcvNULL) == gcvSTATUS_NOT_FOUND) + { + /*printf("Vidmem not found for process:%d\n", queue->processID);*/ + status = gcvSTATUS_OK; + break; + } +#else + if ((node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + && (node->VidMem.logical != gcvNULL) + ) + { + gcmkERR_BREAK( + gckKERNEL_UnmapVideoMemory(record->kernel, + node->VidMem.logical, + record->processID, + node->VidMem.bytes)); + node->VidMem.logical = gcvNULL; + } +#endif +#endif + + /* Free video memory. */ + status = + gckVIDMEM_Free(record->info.u.FreeVideoMemory.node); + + break; + + case gcvHAL_WRITE_DATA: +#ifndef __QNXNTO__ + /* Convert physical into logical address. */ + gcmkERR_BREAK( + gckOS_MapPhysical(Event->os, + record->info.u.WriteData.address, + gcmSIZEOF(gctUINT32), + &logical)); + + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + logical, + record->info.u.WriteData.data)); + + /* Unmap the physical memory. */ + gcmkERR_BREAK( + gckOS_UnmapPhysical(Event->os, + logical, + gcmSIZEOF(gctUINT32))); +#else + /* Write data. */ + gcmkERR_BREAK( + gckOS_WriteMemory(Event->os, + (gctPOINTER) + record->info.u.WriteData.address, + record->info.u.WriteData.data)); +#endif + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_UNLOCK_VIDEO_MEMORY: 0x%x", + record->info.u.UnlockVideoMemory.node); + + /* Save node information before it disappears. */ +#if gcdSECURE_USER + node = event->event.u.UnlockVideoMemory.node; + if (node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + logical = gcvNULL; + bytes = 0; + } + else + { + logical = node->Virtual.logical; + bytes = node->Virtual.bytes; + } +#endif + + /* Unlock. */ + status = gckVIDMEM_Unlock( + Event->kernel, + record->info.u.UnlockVideoMemory.node, + record->info.u.UnlockVideoMemory.type, + gcvNULL); + +#if gcdSECURE_USER + if (gcmIS_SUCCESS(status) && (logical != gcvNULL)) + { + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Event->kernel, + cache, + logical, + bytes)); + } +#endif + break; + + case gcvHAL_SIGNAL: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_SIGNAL: 0x%x", + record->info.u.Signal.signal); + +#ifdef __QNXNTO__ + if ((record->info.u.Signal.coid == 0) + && (record->info.u.Signal.rcvid == 0) + ) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + record->info.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + record->info.u.Signal.signal, + record->info.u.Signal.rcvid, + record->info.u.Signal.coid)); + } +#else + /* Set signal. */ + if (record->info.u.Signal.process == gcvNULL) + { + /* Kernel signal. */ + gcmkERR_BREAK( + gckOS_Signal(Event->os, + record->info.u.Signal.signal, + gcvTRUE)); + } + else + { + /* User signal. */ + gcmkERR_BREAK( + gckOS_UserSignal(Event->os, + record->info.u.Signal.signal, + record->info.u.Signal.process)); + } + + gcmkASSERT(record->info.u.Signal.auxSignal == gcvNULL); +#endif + break; + + case gcvHAL_UNMAP_USER_MEMORY: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_UNMAP_USER_MEMORY: 0x%x", + record->info.u.UnmapUserMemory.info); + + /* Unmap the user memory. */ + status = gckOS_UnmapUserMemoryEx( + Event->os, + Event->kernel->core, + record->info.u.UnmapUserMemory.memory, + record->info.u.UnmapUserMemory.size, + record->info.u.UnmapUserMemory.info, + record->info.u.UnmapUserMemory.address); + +#if gcdSECURE_USER + if (gcmIS_SUCCESS(status)) + { + gcmkVERIFY_OK(gckKERNEL_FlushTranslationCache( + Event->kernel, + cache, + event->event.u.UnmapUserMemory.memory, + event->event.u.UnmapUserMemory.size)); + } +#endif + gcmkVERIFY_OK(gckKERNEL_RemoveProcessDB( + Event->kernel, + record->processID, gcvDB_MAP_USER_MEMORY, + record->info.u.UnmapUserMemory.memory)); + break; + + case gcvHAL_TIMESTAMP: + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "gcvHAL_TIMESTAMP: %d %d", + record->info.u.TimeStamp.timer, + record->info.u.TimeStamp.request); + + /* Process the timestamp. */ + switch (record->info.u.TimeStamp.request) + { + case 0: + status = gckOS_GetTime(&Event->kernel->timers[ + record->info.u.TimeStamp.timer]. + stopTime); + break; + + case 1: + status = gckOS_GetTime(&Event->kernel->timers[ + record->info.u.TimeStamp.timer]. + startTime); + break; + + default: + gcmkTRACE_ZONE_N( + gcvLEVEL_ERROR, gcvZONE_EVENT, + gcmSIZEOF(record->info.u.TimeStamp.request), + "Invalid timestamp request: %d", + record->info.u.TimeStamp.request + ); + + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + break; + + case gcvHAL_COMMIT_DONE: + break; + + default: + /* Invalid argument. */ + gcmkTRACE_ZONE_N( + gcvLEVEL_ERROR, gcvZONE_EVENT, + gcmSIZEOF(record->info.command), + "Unknown event type: %d", + record->info.command + ); + + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + + /* Make sure there are no errors generated. */ + if (gcmIS_ERROR(status)) + { + gcmkTRACE_ZONE_N( + gcvLEVEL_WARNING, gcvZONE_EVENT, + gcmSIZEOF(status), + "Event produced status: %d(%s)", + status, gckOS_DebugStatus2Name(status)); + } + + /* Free the event. */ + gcmkVERIFY_OK(gckEVENT_FreeRecord(Event, record)); + } + + if (recordNext == gcvNULL) + { + break; + } + } + + /* Increase the number of free events. */ + gcmkONERROR(gckOS_AtomIncrement(Event->os, Event->freeAtom, &free)); + + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_EVENT, + "Handled interrupt 0x%x", mask); + + /* Suspend interrupts. */ + gcmkONERROR(gckOS_SuspendInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvTRUE; + + /* Mark pending interrupt as handled. */ +#if gcdSMP + gckOS_AtomClearMask(Event->pending, mask); +#elif defined(__QNXNTO__) + atomic_clr(&Event->pending, mask); +#else + Event->pending &= ~mask; +#endif + + /* Resume interrupts. */ + gcmkONERROR(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core)); + suspended = gcvFALSE; + } + + if (IDs == 0) + { + gcmkONERROR(_TryToIdleGPU(Event)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + } + + if (suspended) + { + /* Resume interrupts. */ + gcmkVERIFY_OK(gckOS_ResumeInterruptEx(Event->os, Event->kernel->core)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckEVENT_FreeProcess +** +** Free all events owned by a particular process ID. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctUINT32 ProcessID +** Process ID of the process to be freed up. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_FreeProcess( + IN gckEVENT Event, + IN gctUINT32 ProcessID + ) +{ + gctSIZE_T i; + gctBOOL acquired = gcvFALSE; + gcsEVENT_PTR record, next; + gceSTATUS status; + gcsEVENT_PTR deleteHead, deleteTail; + + gcmkHEADER_ARG("Event=0x%x ProcessID=%d", Event, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Walk through all queues. */ + for (i = 0; i < gcmCOUNTOF(Event->queues); ++i) + { + if (Event->queues[i].head != gcvNULL) + { + /* Grab the event queue mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Event->os, + Event->eventQueueMutex, + gcvINFINITE)); + acquired = gcvTRUE; + + /* Grab the mutex head. */ + record = Event->queues[i].head; + Event->queues[i].head = gcvNULL; + Event->queues[i].tail = gcvNULL; + deleteHead = gcvNULL; + deleteTail = gcvNULL; + + while (record != gcvNULL) + { + next = record->next; + if (record->processID == ProcessID) + { + if (deleteHead == gcvNULL) + { + deleteHead = record; + } + else + { + deleteTail->next = record; + } + + deleteTail = record; + } + else + { + if (Event->queues[i].head == gcvNULL) + { + Event->queues[i].head = record; + } + else + { + Event->queues[i].tail->next = record; + } + + Event->queues[i].tail = record; + } + + record->next = gcvNULL; + record = next; + } + + /* Release the mutex queue. */ + gcmkONERROR(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + acquired = gcvFALSE; + + /* Loop through the entire list of events. */ + for (record = deleteHead; record != gcvNULL; record = next) + { + /* Get the next event record. */ + next = record->next; + + /* Free the event record. */ + gcmkONERROR(gckEVENT_FreeRecord(Event, record)); + } + } + } + + gcmkONERROR(_TryToIdleGPU(Event)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Release the event queue mutex. */ + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Event->os, Event->eventQueueMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** gckEVENT_Stop +** +** Stop the hardware using the End event mechanism. +** +** INPUT: +** +** gckEVENT Event +** Pointer to an gckEVENT object. +** +** gctUINT32 ProcessID +** Process ID Logical belongs. +** +** gctPHYS_ADDR Handle +** Physical address handle. If gcvNULL it is video memory. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIGNAL Signal +** Pointer to the signal to trigger. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckEVENT_Stop( + IN gckEVENT Event, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Logical, + IN gctSIGNAL Signal, + IN OUT gctSIZE_T * waitSize + ) +{ + gceSTATUS status; + /* gctSIZE_T waitSize;*/ + gcsEVENT_PTR record; + gctUINT8 id = 0xFF; + + gcmkHEADER_ARG("Event=0x%x ProcessID=%u Handle=0x%x Logical=0x%x " + "Signal=0x%x", + Event, ProcessID, Handle, Logical, Signal); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Event, gcvOBJ_EVENT); + + /* Submit the current event queue. */ + gcmkONERROR(gckEVENT_Submit(Event, gcvTRUE, gcvFALSE)); + + gcmkONERROR(gckEVENT_GetEvent(Event, gcvTRUE, &id, gcvKERNEL_PIXEL)); + + /* Allocate a record. */ + gcmkONERROR(gckEVENT_AllocateRecord(Event, gcvTRUE, &record)); + + /* Initialize the record. */ + record->next = gcvNULL; + record->processID = ProcessID; + record->info.command = gcvHAL_SIGNAL; + record->info.u.Signal.signal = Signal; +#ifdef __QNXNTO__ + record->info.u.Signal.coid = 0; + record->info.u.Signal.rcvid = 0; +#endif + record->info.u.Signal.auxSignal = gcvNULL; + record->info.u.Signal.process = gcvNULL; + + /* Append the record. */ + Event->queues[id].head = record; + + /* Replace last WAIT with END. */ + gcmkONERROR(gckHARDWARE_End( + Event->kernel->hardware, Logical, waitSize + )); + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Flush the cache for the END. */ + gcmkONERROR(gckOS_CacheClean( + Event->os, + ProcessID, + gcvNULL, + Handle, + Logical, + *waitSize + )); +#endif + + /* Wait for the signal. */ + gcmkONERROR(gckOS_WaitSignal(Event->os, Signal, gcvINFINITE)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +static void +_PrintRecord( + gcsEVENT_PTR record + ) +{ + switch (record->info.command) + { + case gcvHAL_FREE_NON_PAGED_MEMORY: + gcmkPRINT(" gcvHAL_FREE_NON_PAGED_MEMORY"); + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + gcmkPRINT(" gcvHAL_FREE_CONTIGUOUS_MEMORY"); + break; + + case gcvHAL_FREE_VIDEO_MEMORY: + gcmkPRINT(" gcvHAL_FREE_VIDEO_MEMORY"); + break; + + case gcvHAL_WRITE_DATA: + gcmkPRINT(" gcvHAL_WRITE_DATA"); + break; + + case gcvHAL_UNLOCK_VIDEO_MEMORY: + gcmkPRINT(" gcvHAL_UNLOCK_VIDEO_MEMORY"); + break; + + case gcvHAL_SIGNAL: + gcmkPRINT(" gcvHAL_SIGNAL process=%d signal=0x%x", + record->info.u.Signal.process, + record->info.u.Signal.signal); + break; + + case gcvHAL_UNMAP_USER_MEMORY: + gcmkPRINT(" gcvHAL_UNMAP_USER_MEMORY"); + break; + + case gcvHAL_TIMESTAMP: + gcmkPRINT(" gcvHAL_TIMESTAMP"); + break; + + case gcvHAL_COMMIT_DONE: + gcmkPRINT(" gcvHAL_COMMIT_DONE"); + break; + + default: + gcmkPRINT(" Illegal Event %d", record->info.command); + break; + } +} + +/******************************************************************************* +** gckEVENT_Dump +** +** Dump record in event queue when stuck happens. +** No protection for the event queue. +**/ +gceSTATUS +gckEVENT_Dump( + IN gckEVENT Event + ) +{ + gcsEVENT_QUEUE_PTR queueHead = Event->queueHead; + gcsEVENT_QUEUE_PTR queue; + gcsEVENT_PTR record = gcvNULL; + gctINT i; + + gcmkHEADER_ARG("Event=0x%x", Event); + + gcmkPRINT("**************************\n"); + gcmkPRINT("*** EVENT STATE DUMP ***\n"); + gcmkPRINT("**************************\n"); + + + gcmkPRINT(" Unsumbitted Event:"); + while(queueHead) + { + queue = queueHead; + record = queueHead->head; + + gcmkPRINT(" [%x]:", queue); + while(record) + { + _PrintRecord(record); + record = record->next; + } + + if (queueHead == Event->queueTail) + { + queueHead = gcvNULL; + } + else + { + queueHead = queueHead->next; + } + } + + gcmkPRINT(" Untriggered Event:"); + for (i = 0; i < 30; i++) + { + queue = &Event->queues[i]; + record = queue->head; + + gcmkPRINT(" [%d]:", i); + while(record) + { + _PrintRecord(record); + record = record->next; + } + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_heap.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_heap.c new file mode 100644 index 0000000..c68e0c1 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_heap.c @@ -0,0 +1,861 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/** +** @file +** gckHEAP object for kernel HAL layer. The heap implemented here is an arena- +** based memory allocation. An arena-based memory heap allocates data quickly +** from specified arenas and reduces memory fragmentation. +** +*/ +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_HEAP + +/******************************************************************************* +***** Structures *************************************************************** +*******************************************************************************/ + +#define gcdIN_USE ((gcskNODE_PTR) ~0) + +typedef struct _gcskNODE * gcskNODE_PTR; +typedef struct _gcskNODE +{ + /* Number of byets in node. */ + gctSIZE_T bytes; + + /* Pointer to next free node, or gcvNULL to mark the node as freed, or + ** gcdIN_USE to mark the node as used. */ + gcskNODE_PTR next; + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + /* Time stamp of allocation. */ + gctUINT64 timeStamp; +#endif +} +gcskNODE; + +typedef struct _gcskHEAP * gcskHEAP_PTR; +typedef struct _gcskHEAP +{ + /* Linked list. */ + gcskHEAP_PTR next; + gcskHEAP_PTR prev; + + /* Heap size. */ + gctSIZE_T size; + + /* Free list. */ + gcskNODE_PTR freeList; +} +gcskHEAP; + +struct _gckHEAP +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to a gckOS object. */ + gckOS os; + + /* Locking mutex. */ + gctPOINTER mutex; + + /* Allocation parameters. */ + gctSIZE_T allocationSize; + + /* Heap list. */ + gcskHEAP_PTR heap; +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gctUINT64 timeStamp; +#endif + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Profile information. */ + gctUINT32 allocCount; + gctUINT64 allocBytes; + gctUINT64 allocBytesMax; + gctUINT64 allocBytesTotal; + gctUINT32 heapCount; + gctUINT32 heapCountMax; + gctUINT64 heapMemory; + gctUINT64 heapMemoryMax; +#endif +}; + +/******************************************************************************* +***** Static Support Functions ************************************************* +*******************************************************************************/ + +#if gcmIS_DEBUG(gcdDEBUG_CODE) +static gctSIZE_T +_DumpHeap( + IN gcskHEAP_PTR Heap + ) +{ + gctPOINTER p; + gctSIZE_T leaked = 0; + + /* Start at first node. */ + for (p = Heap + 1;;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + /* Check if this is a used node. */ + if (node->next == gcdIN_USE) + { + /* Print the leaking node. */ + gcmkTRACE_ZONE(gcvLEVEL_WARNING, gcvZONE_HEAP, + "Detected leaking: node=0x%x bytes=%lu timeStamp=%llu " + "(%08X %c%c%c%c)", + node, node->bytes, node->timeStamp, + ((gctUINT32_PTR) (node + 1))[0], + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[0]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[1]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[2]), + gcmPRINTABLE(((gctUINT8_PTR) (node + 1))[3])); + + /* Add leaking byte count. */ + leaked += node->bytes; + } + + /* Test for end of heap. */ + if (node->bytes == 0) + { + break; + } + + else + { + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + } + + /* Return the number of leaked bytes. */ + return leaked; +} +#endif + +static gceSTATUS +_CompactKernelHeap( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap, next; + gctPOINTER p; + gcskHEAP_PTR freeList = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = next) + { + gcskNODE_PTR lastFree = gcvNULL; + + /* Zero out the free list. */ + heap->freeList = gcvNULL; + + /* Start at the first node. */ + for (p = (gctUINT8_PTR) (heap + 1);;) + { + /* Convert the pointer. */ + gcskNODE_PTR node = (gcskNODE_PTR) p; + + gcmkASSERT(p <= (gctPOINTER) ((gctUINT8_PTR) (heap + 1) + heap->size)); + + /* Test if this node not used. */ + if (node->next != gcdIN_USE) + { + /* Test if this is the end of the heap. */ + if (node->bytes == 0) + { + break; + } + + /* Test of this is the first free node. */ + else if (lastFree == gcvNULL) + { + /* Initialzie the free list. */ + heap->freeList = node; + lastFree = node; + } + + else + { + /* Test if this free node is contiguous with the previous + ** free node. */ + if ((gctUINT8_PTR) lastFree + lastFree->bytes == p) + { + /* Just increase the size of the previous free node. */ + lastFree->bytes += node->bytes; + } + else + { + /* Add to linked list. */ + lastFree->next = node; + lastFree = node; + } + } + } + + /* Move to next node. */ + p = (gctUINT8_PTR) node + node->bytes; + } + + /* Mark the end of the chain. */ + if (lastFree != gcvNULL) + { + lastFree->next = gcvNULL; + } + + /* Get next heap. */ + next = heap->next; + + /* Check if the entire heap is free. */ + if ((heap->freeList != gcvNULL) + && (heap->freeList->bytes == heap->size - gcmSIZEOF(gcskNODE)) + ) + { + /* Remove the heap from the linked list. */ + if (heap->prev == gcvNULL) + { + Heap->heap = next; + } + else + { + heap->prev->next = next; + } + + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Update profiling. */ + Heap->heapCount -= 1; + Heap->heapMemory -= heap->size + gcmSIZEOF(gcskHEAP); +#endif + + /* Add this heap to the list of heaps that need to be freed. */ + heap->next = freeList; + freeList = heap; + } + } + + if (freeList != gcvNULL) + { + /* Release the mutex, remove any chance for a dead lock. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Free all heaps in the free list. */ + for (heap = freeList; heap != gcvNULL; heap = next) + { + /* Get pointer to the next heap. */ + next = heap->next; + + /* Free the heap. */ + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Freeing heap 0x%x (%lu bytes)", + heap, heap->size + gcmSIZEOF(gcskHEAP)); + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap)); + } + + /* Acquire the mutex again. */ + gcmkVERIFY_OK( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +***** gckHEAP API Code ********************************************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckHEAP_Construct +** +** Construct a new gckHEAP object. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctSIZE_T AllocationSize +** Minimum size per arena. +** +** OUTPUT: +** +** gckHEAP * Heap +** Pointer to a variable that will hold the pointer to the gckHEAP +** object. +*/ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ) +{ + gceSTATUS status; + gckHEAP heap = gcvNULL; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x AllocationSize=%lu", Os, AllocationSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Heap != gcvNULL); + + /* Allocate the gckHEAP object. */ + gcmkONERROR(gckOS_AllocateMemory(Os, + gcmSIZEOF(struct _gckHEAP), + &pointer)); + + heap = pointer; + + /* Initialize the gckHEAP object. */ + heap->object.type = gcvOBJ_HEAP; + heap->os = Os; + heap->allocationSize = AllocationSize; + heap->heap = gcvNULL; +#if gcmIS_DEBUG(gcdDEBUG_CODE) + heap->timeStamp = 0; +#endif + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Zero the counters. */ + heap->allocCount = 0; + heap->allocBytes = 0; + heap->allocBytesMax = 0; + heap->allocBytesTotal = 0; + heap->heapCount = 0; + heap->heapCountMax = 0; + heap->heapMemory = 0; + heap->heapMemoryMax = 0; +#endif + + /* Create the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &heap->mutex)); + + /* Return the pointer to the gckHEAP object. */ + *Heap = heap; + + /* Success. */ + gcmkFOOTER_ARG("*Heap=0x%x", *Heap); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (heap != gcvNULL) + { + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Os, heap)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Destroy +** +** Destroy a gckHEAP object. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ) +{ + gcskHEAP_PTR heap; +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gctSIZE_T leaked = 0; +#endif + + gcmkHEADER_ARG("Heap=0x%x", Heap); + + for (heap = Heap->heap; heap != gcvNULL; heap = Heap->heap) + { + /* Unlink heap from linked list. */ + Heap->heap = heap->next; + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + /* Check for leaked memory. */ + leaked += _DumpHeap(heap); +#endif + + /* Free the heap. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, heap)); + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Heap->os, Heap->mutex)); + + /* Free the heap structure. */ + gcmkVERIFY_OK(gckOS_FreeMemory(Heap->os, Heap)); + + /* Success. */ +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gcmkFOOTER_ARG("leaked=%lu", leaked); +#else + gcmkFOOTER_NO(); +#endif + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckHEAP_Allocate +** +** Allocate data from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the address of the allocated +** memory. +*/ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctBOOL acquired = gcvFALSE; + gcskHEAP_PTR heap; + gceSTATUS status; + gctSIZE_T bytes; + gcskNODE_PTR node, used, prevFree = gcvNULL; + gctPOINTER memory = gcvNULL; + + gcmkHEADER_ARG("Heap=0x%x Bytes=%lu", Heap, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Determine number of bytes required for a node. */ + bytes = gcmALIGN(Bytes + gcmSIZEOF(gcskNODE), 8); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Check if this allocation is bigger than the default allocation size. */ + if (bytes > Heap->allocationSize - gcmSIZEOF(gcskHEAP) - gcmSIZEOF(gcskNODE)) + { + /* Adjust allocation size. */ + Heap->allocationSize = bytes * 2; + } + + else if (Heap->heap != gcvNULL) + { + gctINT i; + + /* 2 retries, since we might need to compact. */ + for (i = 0; i < 2; ++i) + { + /* Walk all the heaps. */ + for (heap = Heap->heap; heap != gcvNULL; heap = heap->next) + { + /* Check if this heap has enough bytes to hold the request. */ + if (bytes <= heap->size - gcmSIZEOF(gcskNODE)) + { + prevFree = gcvNULL; + + /* Walk the chain of free nodes. */ + for (node = heap->freeList; + node != gcvNULL; + node = node->next + ) + { + gcmkASSERT(node->next != gcdIN_USE); + + /* Check if this free node has enough bytes. */ + if (node->bytes >= bytes) + { + /* Use the node. */ + goto UseNode; + } + + /* Save current free node for linked list management. */ + prevFree = node; + } + } + } + + if (i == 0) + { + /* Compact the heap. */ + gcmkVERIFY_OK(_CompactKernelHeap(Heap)); + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "===== KERNEL HEAP ====="); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of allocations : %12u", + Heap->allocCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of bytes allocated : %12llu", + Heap->allocBytes); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum allocation size : %12llu", + Heap->allocBytesMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Total number of bytes allocated : %12llu", + Heap->allocBytesTotal); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Number of heaps : %12u", + Heap->heapCount); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Heap memory in bytes : %12llu", + Heap->heapMemory); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum number of heaps : %12u", + Heap->heapCountMax); + gcmkTRACE_ZONE(gcvLEVEL_VERBOSE, gcvZONE_HEAP, + "Maximum heap memory in bytes : %12llu", + Heap->heapMemoryMax); +#endif + } + } + } + + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + acquired = gcvFALSE; + + /* Allocate a new heap. */ + gcmkONERROR( + gckOS_AllocateMemory(Heap->os, + Heap->allocationSize, + &memory)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_HEAP, + "Allocated heap 0x%x (%lu bytes)", + memory, Heap->allocationSize); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + /* Use the allocated memory as the heap. */ + heap = (gcskHEAP_PTR) memory; + + /* Insert this heap to the head of the chain. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + heap->size = Heap->allocationSize - gcmSIZEOF(gcskHEAP); + + if (heap->next != gcvNULL) + { + heap->next->prev = heap; + } + Heap->heap = heap; + + /* Mark the end of the heap. */ + node = (gcskNODE_PTR) ( (gctUINT8_PTR) heap + + Heap->allocationSize + - gcmSIZEOF(gcskNODE) + ); + node->bytes = 0; + node->next = gcvNULL; + + /* Create a free list. */ + node = (gcskNODE_PTR) (heap + 1); + heap->freeList = node; + + /* Initialize the free list. */ + node->bytes = heap->size - gcmSIZEOF(gcskNODE); + node->next = gcvNULL; + + /* No previous free. */ + prevFree = gcvNULL; + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Update profiling. */ + Heap->heapCount += 1; + Heap->heapMemory += Heap->allocationSize; + + if (Heap->heapCount > Heap->heapCountMax) + { + Heap->heapCountMax = Heap->heapCount; + } + if (Heap->heapMemory > Heap->heapMemoryMax) + { + Heap->heapMemoryMax = Heap->heapMemory; + } +#endif + +UseNode: + /* Verify some stuff. */ + gcmkASSERT(heap != gcvNULL); + gcmkASSERT(node != gcvNULL); + gcmkASSERT(node->bytes >= bytes); + + if (heap->prev != gcvNULL) + { + /* Unlink the heap from the linked list. */ + heap->prev->next = heap->next; + if (heap->next != gcvNULL) + { + heap->next->prev = heap->prev; + } + + /* Move the heap to the front of the list. */ + heap->next = Heap->heap; + heap->prev = gcvNULL; + Heap->heap = heap; + heap->next->prev = heap; + } + + /* Check if there is enough free space left after usage for another free + ** node. */ + if (node->bytes - bytes >= gcmSIZEOF(gcskNODE)) + { + /* Allocated used space from the back of the free list. */ + used = (gcskNODE_PTR) ((gctUINT8_PTR) node + node->bytes - bytes); + + /* Adjust the number of free bytes. */ + node->bytes -= bytes; + gcmkASSERT(node->bytes >= gcmSIZEOF(gcskNODE)); + } + else + { + /* Remove this free list from the chain. */ + if (prevFree == gcvNULL) + { + heap->freeList = node->next; + } + else + { + prevFree->next = node->next; + } + + /* Consume the entire free node. */ + used = (gcskNODE_PTR) node; + bytes = node->bytes; + } + + /* Mark node as used. */ + used->bytes = bytes; + used->next = gcdIN_USE; +#if gcmIS_DEBUG(gcdDEBUG_CODE) + used->timeStamp = ++Heap->timeStamp; +#endif + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Update profile counters. */ + Heap->allocCount += 1; + Heap->allocBytes += bytes; + Heap->allocBytesMax = gcmMAX(Heap->allocBytes, Heap->allocBytesMax); + Heap->allocBytesTotal += bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Return pointer to memory. */ + *Memory = used + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + } + + if (memory != gcvNULL) + { + /* Free the heap memory. */ + gckOS_FreeMemory(Heap->os, memory); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckHEAP_Free +** +** Free allocated memory from the heap. +** +** INPUT: +** +** gckHEAP Heap +** Pointer to a gckHEAP object. +** +** IN gctPOINTER Memory +** Pointer to memory to free. +** +** OUTPUT: +** +** NOTHING. +*/ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Memory + ) +{ + gcskNODE_PTR node; + gceSTATUS status; + + gcmkHEADER_ARG("Heap=0x%x Memory=0x%x", Heap, Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(Heap->os, Heap->mutex, gcvINFINITE)); + + /* Pointer to structure. */ + node = (gcskNODE_PTR) Memory - 1; + + /* Mark the node as freed. */ + node->next = gcvNULL; + +#if VIVANTE_PROFILER || gcmIS_DEBUG(gcdDEBUG_CODE) + /* Update profile counters. */ + Heap->allocBytes -= node->bytes; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Heap->os, Heap->mutex)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if VIVANTE_PROFILER +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ) +{ + gcmkHEADER_ARG("Heap=0x%x", Heap); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Heap, gcvOBJ_HEAP); + + /* Zero the counters. */ + Heap->allocCount = 0; + Heap->allocBytes = 0; + Heap->allocBytesMax = 0; + Heap->allocBytesTotal = 0; + Heap->heapCount = 0; + Heap->heapCountMax = 0; + Heap->heapMemory = 0; + Heap->heapMemoryMax = 0; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +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; +} +#endif /* VIVANTE_PROFILER */ + +/******************************************************************************* +***** Test Code **************************************************************** +*******************************************************************************/ + diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_interrupt_vg.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_interrupt_vg.c new file mode 100644 index 0000000..e2f84f6 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_interrupt_vg.c @@ -0,0 +1,876 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#if gcdENABLE_VG + +/******************************************************************************\ +*********************** Support Functions and Definitions ********************** +\******************************************************************************/ + +/* Interruot statistics will be accumulated if not zero. */ +#define gcmENABLE_INTERRUPT_STATISTICS 0 + +#define _GC_OBJ_ZONE gcvZONE_INTERRUPT + +/* Object structure. */ +struct _gckVGINTERRUPT +{ + /* Object. */ + gcsOBJECT object; + + /* gckVGKERNEL pointer. */ + gckVGKERNEL kernel; + + /* gckOS pointer. */ + gckOS os; + + /* Interrupt handlers. */ + gctINTERRUPT_HANDLER handlers[32]; + + /* Main interrupt handler thread. */ + gctTHREAD handler; + gctBOOL terminate; + + /* Interrupt FIFO. */ + gctSEMAPHORE fifoValid; + gctUINT32 fifo[256]; + gctUINT fifoItems; + gctUINT8 head; + gctUINT8 tail; + + /* Interrupt statistics. */ +#if gcmENABLE_INTERRUPT_STATISTICS + gctUINT maxFifoItems; + gctUINT fifoOverflow; + gctUINT maxSimultaneous; + gctUINT multipleCount; +#endif +}; + + +/******************************************************************************* +** +** _ProcessInterrupt +** +** The interrupt processor. +** +** INPUT: +** +** ThreadParameter +** Pointer to the gckVGINTERRUPT object. +** +** OUTPUT: +** +** Nothing. +*/ + +#if gcmENABLE_INTERRUPT_STATISTICS +static void +_ProcessInterrupt( + gckVGINTERRUPT Interrupt, + gctUINT_PTR TriggeredCount + ) +#else +static void +_ProcessInterrupt( + gckVGINTERRUPT Interrupt + ) +#endif +{ + gceSTATUS status; + gctUINT32 triggered; + gctUINT i; + + /* Advance to the next entry. */ + Interrupt->tail += 1; + Interrupt->fifoItems -= 1; + + /* Get the interrupt value. */ + triggered = Interrupt->fifo[Interrupt->tail]; + gcmkASSERT(triggered != 0); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s: triggered=0x%08X\n", + __FUNCTION__, + triggered + ); + + /* Walk through all possible interrupts. */ + for (i = 0; i < gcmSIZEOF(Interrupt->handlers); i += 1) + { + /* Test if interrupt happened. */ + if ((triggered & 1) == 1) + { +#if gcmENABLE_INTERRUPT_STATISTICS + if (TriggeredCount != gcvNULL) + { + (* TriggeredCount) += 1; + } +#endif + + /* Make sure we have valid handler. */ + if (Interrupt->handlers[i] == gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s: Interrupt %d isn't registered.\n", + __FUNCTION__, i + ); + } + else + { + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s: interrupt=%d\n", + __FUNCTION__, + i + ); + + /* Call the handler. */ + status = Interrupt->handlers[i] (Interrupt->kernel); + + if (gcmkIS_ERROR(status)) + { + /* Failed to signal the semaphore. */ + gcmkTRACE( + gcvLEVEL_ERROR, + "%s: Error %d incrementing the semaphore #%d.\n", + __FUNCTION__, status, i + ); + } + } + } + + /* Next interrupt. */ + triggered >>= 1; + + /* No more interrupts to handle? */ + if (triggered == 0) + { + break; + } + } +} + + +/******************************************************************************* +** +** _MainInterruptHandler +** +** The main interrupt thread serves the interrupt FIFO and calls registered +** handlers for the interrupts that occured. The handlers are called in the +** sequence interrupts occured with the exception when multiple interrupts +** occured at the same time. In that case the handler calls are "sorted" by +** the interrupt number therefore giving the interrupts with lower numbers +** higher priority. +** +** INPUT: +** +** ThreadParameter +** Pointer to the gckVGINTERRUPT object. +** +** OUTPUT: +** +** Nothing. +*/ + +static gctTHREADFUNCRESULT gctTHREADFUNCTYPE +_MainInterruptHandler( + gctTHREADFUNCPARAMETER ThreadParameter + ) +{ + gceSTATUS status; + gckVGINTERRUPT interrupt; + +#if gcmENABLE_INTERRUPT_STATISTICS + gctUINT count; +#endif + + /* Cast the object. */ + interrupt = (gckVGINTERRUPT) ThreadParameter; + + /* Enter the loop. */ + while (gcvTRUE) + { + /* Wait for an interrupt. */ + status = gckOS_DecrementSemaphore(interrupt->os, interrupt->fifoValid); + + /* Error? */ + if (gcmkIS_ERROR(status)) + { + break; + } + + /* System termination request? */ + if (status == gcvSTATUS_TERMINATE) + { + break; + } + + /* Driver is shutting down? */ + if (interrupt->terminate) + { + break; + } + +#if gcmENABLE_INTERRUPT_STATISTICS + /* Reset triggered count. */ + count = 0; + + /* Process the interrupt. */ + _ProcessInterrupt(interrupt, &count); + + /* Update conters. */ + if (count > interrupt->maxSimultaneous) + { + interrupt->maxSimultaneous = count; + } + + if (count > 1) + { + interrupt->multipleCount += 1; + } +#else + /* Process the interrupt. */ + _ProcessInterrupt(interrupt); +#endif + } + + return 0; +} + + +/******************************************************************************* +** +** _StartInterruptHandler / _StopInterruptHandler +** +** Main interrupt handler routine control. +** +** INPUT: +** +** ThreadParameter +** Pointer to the gckVGINTERRUPT object. +** +** OUTPUT: +** +** Nothing. +*/ + +static gceSTATUS +_StartInterruptHandler( + gckVGINTERRUPT Interrupt + ) +{ + gceSTATUS status, last; + + do + { + /* Objects must not be already created. */ + gcmkASSERT(Interrupt->fifoValid == gcvNULL); + gcmkASSERT(Interrupt->handler == gcvNULL); + + /* Reset the termination request. */ + Interrupt->terminate = gcvFALSE; + +#if !gcdENABLE_INFINITE_SPEED_HW + /* Construct the fifo semaphore. */ + gcmkERR_BREAK(gckOS_CreateSemaphoreVG( + Interrupt->os, &Interrupt->fifoValid + )); + + /* Start the interrupt handler thread. */ + gcmkERR_BREAK(gckOS_StartThread( + Interrupt->os, + _MainInterruptHandler, + Interrupt, + &Interrupt->handler + )); +#endif + + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (Interrupt->fifoValid != gcvNULL) + { + gcmkCHECK_STATUS(gckOS_DestroySemaphore( + Interrupt->os, Interrupt->fifoValid + )); + + Interrupt->fifoValid = gcvNULL; + } + + /* Return the status. */ + return status; +} + +static gceSTATUS +_StopInterruptHandler( + gckVGINTERRUPT Interrupt + ) +{ + gceSTATUS status; + + do + { + /* Does the thread exist? */ + if (Interrupt->handler == gcvNULL) + { + /* The semaphore must be NULL as well. */ + gcmkASSERT(Interrupt->fifoValid == gcvNULL); + + /* Success. */ + status = gcvSTATUS_OK; + break; + } + + /* The semaphore must exist as well. */ + gcmkASSERT(Interrupt->fifoValid != gcvNULL); + + /* Set the termination request. */ + Interrupt->terminate = gcvTRUE; + + /* Unlock the thread. */ + gcmkERR_BREAK(gckOS_IncrementSemaphore( + Interrupt->os, Interrupt->fifoValid + )); + + /* Wait until the thread quits. */ + gcmkERR_BREAK(gckOS_StopThread( + Interrupt->os, + Interrupt->handler + )); + + /* Destroy the semaphore. */ + gcmkERR_BREAK(gckOS_DestroySemaphore( + Interrupt->os, Interrupt->fifoValid + )); + + /* Reset handles. */ + Interrupt->handler = gcvNULL; + Interrupt->fifoValid = gcvNULL; + } + while (gcvFALSE); + + /* Return the status. */ + return status; +} + + +/******************************************************************************\ +***************************** Interrupt Object API ***************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckVGINTERRUPT_Construct +** +** Construct an interrupt object. +** +** INPUT: +** +** Kernel +** Pointer to the gckVGKERNEL object. +** +** OUTPUT: +** +** Interrupt +** Pointer to the new gckVGINTERRUPT object. +*/ + +gceSTATUS +gckVGINTERRUPT_Construct( + IN gckVGKERNEL Kernel, + OUT gckVGINTERRUPT * Interrupt + ) +{ + gceSTATUS status; + gckVGINTERRUPT interrupt = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x Interrupt=0x%x", Kernel, Interrupt); + + /* Verify argeuments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interrupt != gcvNULL); + + do + { + /* Allocate the gckVGINTERRUPT structure. */ + gcmkERR_BREAK(gckOS_Allocate( + Kernel->os, + gcmSIZEOF(struct _gckVGINTERRUPT), + (gctPOINTER *) &interrupt + )); + + /* Reset the object data. */ + gcmkVERIFY_OK(gckOS_ZeroMemory( + interrupt, gcmSIZEOF(struct _gckVGINTERRUPT) + )); + + /* Initialize the object. */ + interrupt->object.type = gcvOBJ_INTERRUPT; + + /* Initialize the object pointers. */ + interrupt->kernel = Kernel; + interrupt->os = Kernel->os; + + /* Initialize the current FIFO position. */ + interrupt->head = (gctUINT8)~0; + interrupt->tail = (gctUINT8)~0; + + /* Start the thread. */ + gcmkERR_BREAK(_StartInterruptHandler(interrupt)); + + /* Return interrupt object. */ + *Interrupt = interrupt; + + gcmkFOOTER_ARG("*Interrup=0x%x", *Interrupt); + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (interrupt != gcvNULL) + { + /* Free the gckVGINTERRUPT structure. */ + gcmkVERIFY_OK(gckOS_Free(interrupt->os, interrupt)); + } + + gcmkFOOTER(); + + /* Return the status. */ + return status; +} + + +/******************************************************************************* +** +** gckVGINTERRUPT_Destroy +** +** Destroy an interrupt object. +** +** INPUT: +** +** Interrupt +** Pointer to the gckVGINTERRUPT object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ + +gceSTATUS +gckVGINTERRUPT_Destroy( + IN gckVGINTERRUPT Interrupt + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); + + do + { + /* Stop the interrupt thread. */ + gcmkERR_BREAK(_StopInterruptHandler(Interrupt)); + + /* Mark the object as unknown. */ + Interrupt->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVGINTERRUPT structure. */ + gcmkERR_BREAK(gckOS_Free(Interrupt->os, Interrupt)); + } + while (gcvFALSE); + + gcmkFOOTER(); + + /* Return the status. */ + return status; +} + + +/******************************************************************************* +** +** gckVGINTERRUPT_DumpState +** +** Print the current state of the interrupt manager. +** +** INPUT: +** +** Interrupt +** Pointer to a gckVGINTERRUPT object. +** +** OUTPUT: +** +** Nothing. +*/ + +#if gcvDEBUG +gceSTATUS +gckVGINTERRUPT_DumpState( + IN gckVGINTERRUPT Interrupt + ) +{ + gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); + + /* Print the header. */ + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + "%s: INTERRUPT OBJECT STATUS\n", + __FUNCTION__ + ); + + /* Print statistics. */ +#if gcmENABLE_INTERRUPT_STATISTICS + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " Maximum number of FIFO items accumulated at a single time: %d\n", + Interrupt->maxFifoItems + ); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " Interrupt FIFO overflow happened times: %d\n", + Interrupt->fifoOverflow + ); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " Maximum number of interrupts simultaneously generated: %d\n", + Interrupt->maxSimultaneous + ); + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " Number of times when there were multiple interrupts generated: %d\n", + Interrupt->multipleCount + ); +#endif + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " The current number of entries in the FIFO: %d\n", + Interrupt->fifoItems + ); + + /* Print the FIFO contents. */ + if (Interrupt->fifoItems != 0) + { + gctUINT8 index; + gctUINT8 last; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " FIFO current contents:\n" + ); + + /* Get the current pointers. */ + index = Interrupt->tail; + last = Interrupt->head; + + while (index != last) + { + /* Advance to the next entry. */ + index += 1; + + gcmkTRACE_ZONE( + gcvLEVEL_VERBOSE, gcvZONE_COMMAND, + " %d: 0x%08X\n", + index, Interrupt->fifo[index] + ); + } + } + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} +#endif + + +/******************************************************************************* +** +** gckVGINTERRUPT_Enable +** +** Enable the specified interrupt. +** +** INPUT: +** +** Interrupt +** Pointer to a gckVGINTERRUPT object. +** +** Id +** Pointer to the variable that holds the interrupt number to be +** registered in range 0..31. +** If the value is less then 0, gckVGINTERRUPT_Enable will attempt +** to find an unused interrupt. If such interrupt is found, the number +** will be assigned to the variable if the functuion call succeedes. +** +** Handler +** Pointer to the handler to register for the interrupt. +** +** OUTPUT: +** +** Nothing. +*/ + +gceSTATUS +gckVGINTERRUPT_Enable( + IN gckVGINTERRUPT Interrupt, + IN OUT gctINT32_PTR Id, + IN gctINTERRUPT_HANDLER Handler + ) +{ + gceSTATUS status; + gctINT32 i; + + gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x Handler=0x%x", Interrupt, Id, Handler); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); + gcmkVERIFY_ARGUMENT(Id != gcvNULL); + gcmkVERIFY_ARGUMENT(Handler != gcvNULL); + + do + { + /* See if we need to allocate an ID. */ + if (*Id < 0) + { + /* Find the first unused interrupt handler. */ + for (i = 0; i < gcmCOUNTOF(Interrupt->handlers); ++i) + { + if (Interrupt->handlers[i] == gcvNULL) + { + break; + } + } + + /* No unused innterrupts? */ + if (i == gcmCOUNTOF(Interrupt->handlers)) + { + status = gcvSTATUS_OUT_OF_RESOURCES; + break; + } + + /* Update the interrupt ID. */ + *Id = i; + } + + /* Make sure the ID is in range. */ + else if (*Id >= gcmCOUNTOF(Interrupt->handlers)) + { + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + + /* Set interrupt handler. */ + Interrupt->handlers[*Id] = Handler; + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return the status. */ + return status; +} + + +/******************************************************************************* +** +** gckVGINTERRUPT_Disable +** +** Disable the specified interrupt. +** +** INPUT: +** +** Interrupt +** Pointer to a gckVGINTERRUPT object. +** +** Id +** Interrupt number to be disabled in range 0..31. +** +** OUTPUT: +** +** Nothing. +*/ + +gceSTATUS +gckVGINTERRUPT_Disable( + IN gckVGINTERRUPT Interrupt, + IN gctINT32 Id + ) +{ + gcmkHEADER_ARG("Interrupt=0x%x Id=0x%x", Interrupt, Id); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); + gcmkVERIFY_ARGUMENT((Id >= 0) && (Id < gcmCOUNTOF(Interrupt->handlers))); + + /* Reset interrupt handler. */ + Interrupt->handlers[Id] = gcvNULL; + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckVGINTERRUPT_Enque +** +** Read the interrupt status register and put the value in the interrupt FIFO. +** +** INPUT: +** +** Interrupt +** Pointer to a gckVGINTERRUPT object. +** +** OUTPUT: +** +** Nothing. +*/ + +#ifndef __QNXNTO__ +gceSTATUS +gckVGINTERRUPT_Enque( + IN gckVGINTERRUPT Interrupt + ) +#else +gceSTATUS +gckVGINTERRUPT_Enque( + IN gckVGINTERRUPT Interrupt, + OUT gckOS *Os, + OUT gctSEMAPHORE *Semaphore + ) +#endif +{ + gceSTATUS status; + gctUINT32 triggered; + + gcmkHEADER_ARG("Interrupt=0x%x", Interrupt); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Interrupt, gcvOBJ_INTERRUPT); + +#ifdef __QNXNTO__ + *Os = gcvNULL; + *Semaphore = gcvNULL; +#endif + + do + { + /* Read interrupt status register. */ + gcmkERR_BREAK(gckVGHARDWARE_ReadInterrupt( + Interrupt->kernel->hardware, &triggered + )); + + /* No interrupts to process? */ + if (triggered == 0) + { + status = gcvSTATUS_NOT_OUR_INTERRUPT; + break; + } + + /* FIFO overflow? */ + if (Interrupt->fifoItems == gcmCOUNTOF(Interrupt->fifo)) + { +#if gcmENABLE_INTERRUPT_STATISTICS + Interrupt->fifoOverflow += 1; +#endif + + /* OR the interrupt with the last value in the FIFO. */ + Interrupt->fifo[Interrupt->head] |= triggered; + + /* Success (kind of). */ + status = gcvSTATUS_OK; + } + else + { + /* Advance to the next entry. */ + Interrupt->head += 1; + Interrupt->fifoItems += 1; + +#if gcmENABLE_INTERRUPT_STATISTICS + if (Interrupt->fifoItems > Interrupt->maxFifoItems) + { + Interrupt->maxFifoItems = Interrupt->fifoItems; + } +#endif + + /* Set the new value. */ + Interrupt->fifo[Interrupt->head] = triggered; + +#ifndef __QNXNTO__ + /* Increment the FIFO semaphore. */ + gcmkERR_BREAK(gckOS_IncrementSemaphore( + Interrupt->os, Interrupt->fifoValid + )); +#else + *Os = Interrupt->os; + *Semaphore = Interrupt->fifoValid; +#endif + + /* Windows kills our threads prematurely when the application + exists. Verify here that the thread is still alive. */ + status = gckOS_VerifyThread(Interrupt->os, Interrupt->handler); + + /* Has the thread been prematurely terminated? */ + if (status != gcvSTATUS_OK) + { + /* Process all accumulated interrupts. */ + while (Interrupt->head != Interrupt->tail) + { +#if gcmENABLE_INTERRUPT_STATISTICS + /* Process the interrupt. */ + _ProcessInterrupt(Interrupt, gcvNULL); +#else + /* Process the interrupt. */ + _ProcessInterrupt(Interrupt); +#endif + } + + /* Set success. */ + status = gcvSTATUS_OK; + } + } + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +#endif /* gcdENABLE_VG */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu.c new file mode 100644 index 0000000..cf34118 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu.c @@ -0,0 +1,1404 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_MMU + +typedef enum _gceMMU_TYPE +{ + gcvMMU_USED = (0 << 4), + gcvMMU_SINGLE = (1 << 4), + gcvMMU_FREE = (2 << 4), +} +gceMMU_TYPE; + +#define gcmENTRY_TYPE(x) (x & 0xF0) + +#define gcdMMU_TABLE_DUMP 0 + +/* + gcdMMU_CLEAR_VALUE + + The clear value for the entry of the old MMU. +*/ +#ifndef gcdMMU_CLEAR_VALUE +# define gcdMMU_CLEAR_VALUE 0x00000ABC +#endif + +typedef struct _gcsMMU_STLB *gcsMMU_STLB_PTR; + +typedef struct _gcsMMU_STLB +{ + gctPHYS_ADDR physical; + gctUINT32_PTR logical; + gctSIZE_T size; + gctUINT32 physBase; + gctSIZE_T pageCount; + gctUINT32 mtlbIndex; + gctUINT32 mtlbEntryNum; + gcsMMU_STLB_PTR next; +} gcsMMU_STLB; + +#if gcdSHARED_PAGETABLE +typedef struct _gcsSharedPageTable * gcsSharedPageTable_PTR; +typedef struct _gcsSharedPageTable +{ + /* Shared gckMMU object. */ + gckMMU mmu; + + /* Hardwares which use this shared pagetable. */ + gckHARDWARE hardwares[gcdCORE_COUNT]; + + /* Number of cores use this shared pagetable. */ + gctUINT32 reference; +} +gcsSharedPageTable; + +static gcsSharedPageTable_PTR sharedPageTable = gcvNULL; +#endif + +static gceSTATUS +_Link( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Next + ) +{ + if (Index >= Mmu->pageTableEntries) + { + /* Just move heap pointer. */ + Mmu->heapList = Next; + } + else + { + /* Address page table. */ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + /* Dispatch on node type. */ + switch (gcmENTRY_TYPE(pageTable[Index])) + { + case gcvMMU_SINGLE: + /* Set single index. */ + pageTable[Index] = (Next << 8) | gcvMMU_SINGLE; + break; + + case gcvMMU_FREE: + /* Set index. */ + pageTable[Index + 1] = Next; + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", Index); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* Success. */ + return gcvSTATUS_OK; +} + +static gceSTATUS +_AddFree( + IN gckMMU Mmu, + IN gctUINT32 Index, + IN gctUINT32 Node, + IN gctUINT32 Count + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + + if (Count == 1) + { + /* Initialize a single page node. */ + pageTable[Node] = (~((1U<<8)-1)) | gcvMMU_SINGLE; + } + else + { + /* Initialize the node. */ + pageTable[Node + 0] = (Count << 8) | gcvMMU_FREE; + pageTable[Node + 1] = ~0U; + } + + /* Append the node. */ + return _Link(Mmu, Index, Node); +} + +static gceSTATUS +_Collect( + IN gckMMU Mmu + ) +{ + gctUINT32_PTR pageTable = Mmu->pageTableLogical; + gceSTATUS status; + gctUINT32 i, previous, start = 0, count = 0; + + previous = Mmu->heapList = ~0U; + Mmu->freeNodes = gcvFALSE; + + /* Walk the entire page table. */ + for (i = 0; i < Mmu->pageTableEntries; ++i) + { + /* Dispatch based on type of page. */ + switch (gcmENTRY_TYPE(pageTable[i])) + { + case gcvMMU_USED: + /* Used page, so close any open node. */ + if (count > 0) + { + /* Add the node. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + + /* Reset the node. */ + previous = start; + count = 0; + } + break; + + case gcvMMU_SINGLE: + /* Single free node. */ + if (count++ == 0) + { + /* Start a new node. */ + start = i; + } + break; + + case gcvMMU_FREE: + /* A free node. */ + if (count == 0) + { + /* Start a new node. */ + start = i; + } + + /* Advance the count. */ + count += pageTable[i] >> 8; + + /* Advance the index into the page table. */ + i += (pageTable[i] >> 8) - 1; + break; + + default: + gcmkFATAL("MMU page table correcupted at index %u!", i); + return gcvSTATUS_HEAP_CORRUPTED; + } + } + + /* See if we have an open node left. */ + if (count > 0) + { + /* Add the node to the list. */ + gcmkONERROR(_AddFree(Mmu, previous, start, count)); + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_MMU, + "Performed a garbage collection of the MMU heap."); + + /* Success. */ + return gcvSTATUS_OK; + +OnError: + /* Return the staus. */ + return status; +} + +static gctUINT32 +_SetPage(gctUINT32 PageAddress) +{ + return PageAddress + /* writable */ + | (1 << 2) + /* Ignore exception */ + | (0 << 1) + /* Present */ + | (1 << 0); +} + +static gceSTATUS +_FillFlatMapping( + IN gckMMU Mmu, + IN gctUINT32 PhysBase, + OUT gctSIZE_T Size + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcsMMU_STLB_PTR head = gcvNULL, pre = gcvNULL; + gctUINT32 start = PhysBase & (~gcdMMU_PAGE_64K_MASK); + gctUINT32 end = (PhysBase + Size - 1) & (~gcdMMU_PAGE_64K_MASK); + gctUINT32 mStart = start >> gcdMMU_MTLB_SHIFT; + gctUINT32 mEnd = end >> gcdMMU_MTLB_SHIFT; + gctUINT32 sStart = (start & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT; + gctUINT32 sEnd = (end & gcdMMU_STLB_64K_MASK) >> gcdMMU_STLB_64K_SHIFT; + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); + mutex = gcvTRUE; + + while (mStart <= mEnd) + { + gcmkASSERT(mStart < gcdMMU_MTLB_ENTRY_NUM); + if (*(Mmu->mtlbLogical + mStart) == 0) + { + gcsMMU_STLB_PTR stlb; + gctPOINTER pointer = gcvNULL; + gctUINT32 last = (mStart == mEnd) ? sEnd : (gcdMMU_STLB_64K_ENTRY_NUM - 1); + + gcmkONERROR(gckOS_Allocate(Mmu->os, sizeof(struct _gcsMMU_STLB), &pointer)); + stlb = pointer; + + stlb->mtlbEntryNum = 0; + stlb->next = gcvNULL; + stlb->physical = gcvNULL; + stlb->logical = gcvNULL; + stlb->size = gcdMMU_STLB_64K_SIZE; + stlb->pageCount = 0; + + if (pre == gcvNULL) + { + pre = head = stlb; + } + else + { + gcmkASSERT(pre->next == gcvNULL); + pre->next = stlb; + pre = stlb; + } + + gcmkONERROR( + gckOS_AllocateContiguous(Mmu->os, + gcvFALSE, + &stlb->size, + &stlb->physical, + (gctPOINTER)&stlb->logical)); + + gcmkONERROR(gckOS_ZeroMemory(stlb->logical, stlb->size)); + + gcmkONERROR(gckOS_GetPhysicalAddress( + Mmu->os, + stlb->logical, + &stlb->physBase)); + + if (stlb->physBase & (gcdMMU_STLB_64K_SIZE - 1)) + { + gcmkONERROR(gcvSTATUS_NOT_ALIGNED); + } + + *(Mmu->mtlbLogical + mStart) + = stlb->physBase + /* 64KB page size */ + | (1 << 2) + /* Ignore exception */ + | (0 << 1) + /* Present */ + | (1 << 0); +#if gcdMMU_TABLE_DUMP + gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n", + __FUNCTION__, __LINE__, + mStart, + *(Mmu->mtlbLogical + mStart)); +#endif + + stlb->mtlbIndex = mStart; + stlb->mtlbEntryNum = 1; +#if gcdMMU_TABLE_DUMP + gckOS_Print("%s(%d): STLB: logical:%08x -> physical:%08x\n", + __FUNCTION__, __LINE__, + stlb->logical, + stlb->physBase); +#endif + + while (sStart <= last) + { + gcmkASSERT(!(start & gcdMMU_PAGE_64K_MASK)); + *(stlb->logical + sStart) = _SetPage(start); +#if gcdMMU_TABLE_DUMP + gckOS_Print("%s(%d): insert STLB[%d]: %08x\n", + __FUNCTION__, __LINE__, + sStart, + *(stlb->logical + sStart)); +#endif + /* next page. */ + start += gcdMMU_PAGE_64K_SIZE; + sStart++; + stlb->pageCount++; + } + + sStart = 0; + ++mStart; + } + else + { + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + } + + /* Insert the stlb into staticSTLB. */ + if (Mmu->staticSTLB == gcvNULL) + { + Mmu->staticSTLB = head; + } + else + { + gcmkASSERT(pre == gcvNULL); + gcmkASSERT(pre->next == gcvNULL); + pre->next = Mmu->staticSTLB; + Mmu->staticSTLB = head; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + + return gcvSTATUS_OK; + +OnError: + + /* Roll back. */ + while (head != gcvNULL) + { + pre = head; + head = head->next; + + if (pre->physical != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + pre->physical, + pre->logical, + pre->size)); + } + + if (pre->mtlbEntryNum != 0) + { + gcmkASSERT(pre->mtlbEntryNum == 1); + *(Mmu->mtlbLogical + pre->mtlbIndex) = 0; + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre)); + } + + if (mutex) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + } + + return status; +} + +static gceSTATUS +_SetupDynamicSpace( + IN gckMMU Mmu + ) +{ + gceSTATUS status; + gctINT i; + gctUINT32 physical; + gctINT numEntries; + gctUINT32_PTR pageTable; + gctBOOL acquired = gcvFALSE; + + /* find the start of dynamic address space. */ + for (i = 0; i < gcdMMU_MTLB_ENTRY_NUM; i++) + { + if (!Mmu->mtlbLogical[i]) + { + break; + } + } + + Mmu->dynamicMappingStart = i; + + /* Number of entries in Master TLB for dynamic mapping. */ + numEntries = gcdMMU_MTLB_ENTRY_NUM - i; + + Mmu->pageTableSize = numEntries * 4096; + + Mmu->pageTableEntries = Mmu->pageTableSize / gcmSIZEOF(gctUINT32); + + /* Construct Slave TLB. */ + gcmkONERROR(gckOS_AllocateContiguous(Mmu->os, + gcvFALSE, + &Mmu->pageTableSize, + &Mmu->pageTablePhysical, + (gctPOINTER)&Mmu->pageTableLogical)); + + /* Invalidate all entries. */ + gcmkONERROR(gckOS_ZeroMemory(Mmu->pageTableLogical, + Mmu->pageTableSize)); + + /* Initilization. */ + pageTable = Mmu->pageTableLogical; + pageTable[0] = (Mmu->pageTableEntries << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + Mmu->heapList = 0; + Mmu->freeNodes = gcvFALSE; + + gcmkONERROR(gckOS_GetPhysicalAddress(Mmu->os, + Mmu->pageTableLogical, + &physical)); + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); + acquired = gcvTRUE; + + /* Map to Master TLB. */ + for (; i < gcdMMU_MTLB_ENTRY_NUM; i++) + { + Mmu->mtlbLogical[i] = physical + /* 4KB page size */ + | (0 << 2) + /* Ignore exception */ + | (0 << 1) + /* Present */ + | (1 << 0); +#if gcdMMU_TABLE_DUMP + gckOS_Print("%s(%d): insert MTLB[%d]: %08x\n", + __FUNCTION__, __LINE__, + i, + *(Mmu->mtlbLogical + i)); +#endif + physical += gcdMMU_STLB_4K_SIZE; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + + return gcvSTATUS_OK; + +OnError: + if (Mmu->pageTableLogical) + { + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + Mmu->pageTablePhysical, + (gctPOINTER) Mmu->pageTableLogical, + Mmu->pageTableSize)); + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + } + + return status; +} + +/******************************************************************************* +** +** _Construct +** +** Construct a new gckMMU object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T MmuSize +** Number of bytes for the page table. +** +** OUTPUT: +** +** gckMMU * Mmu +** Pointer to a variable that receives the gckMMU object pointer. +*/ +gceSTATUS +_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ) +{ + gckOS os; + gckHARDWARE hardware; + gceSTATUS status; + gckMMU mmu = gcvNULL; + gctUINT32_PTR pageTable; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Kernel=0x%x MmuSize=%lu", Kernel, MmuSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(MmuSize > 0); + gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Extract the gckHARDWARE object pointer. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Allocate memory for the gckMMU object. */ + gcmkONERROR(gckOS_Allocate(os, sizeof(struct _gckMMU), &pointer)); + + mmu = pointer; + + /* Initialize the gckMMU object. */ + mmu->object.type = gcvOBJ_MMU; + mmu->os = os; + mmu->hardware = hardware; + mmu->pageTableMutex = gcvNULL; + mmu->pageTableLogical = gcvNULL; + mmu->mtlbLogical = gcvNULL; + mmu->staticSTLB = gcvNULL; + mmu->enabled = gcvFALSE; +#ifdef __QNXNTO__ + mmu->nodeList = gcvNULL; + mmu->nodeMutex = gcvNULL; +#endif + + /* Create the page table mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->pageTableMutex)); + +#ifdef __QNXNTO__ + /* Create the node list mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &mmu->nodeMutex)); +#endif + + if (hardware->mmuVersion == 0) + { + mmu->pageTableSize = MmuSize; + + gcmkONERROR( + gckOS_AllocateContiguous(os, + gcvFALSE, + &mmu->pageTableSize, + &mmu->pageTablePhysical, + &pointer)); + + mmu->pageTableLogical = pointer; + + /* Compute number of entries in page table. */ + mmu->pageTableEntries = mmu->pageTableSize / sizeof(gctUINT32); + + /* Mark all pages as free. */ + pageTable = mmu->pageTableLogical; + +#if gcdMMU_CLEAR_VALUE + { + gctUINT32 i; + + for (i = 0; i < mmu->pageTableEntries; ++i) + { + pageTable[i] = gcdMMU_CLEAR_VALUE; + } + } +#endif + + pageTable[0] = (mmu->pageTableEntries << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + mmu->heapList = 0; + mmu->freeNodes = gcvFALSE; + + /* Set page table address. */ + gcmkONERROR( + gckHARDWARE_SetMMU(hardware, (gctPOINTER) mmu->pageTableLogical)); + } + else + { + /* Allocate the 4K mode MTLB table. */ + mmu->mtlbSize = gcdMMU_MTLB_SIZE + 64; + + gcmkONERROR( + gckOS_AllocateContiguous(os, + gcvFALSE, + &mmu->mtlbSize, + &mmu->mtlbPhysical, + &pointer)); + + mmu->mtlbLogical = pointer; + + /* Invalid all the entries. */ + gcmkONERROR( + gckOS_ZeroMemory(pointer, mmu->mtlbSize)); + } + + /* Return the gckMMU object pointer. */ + *Mmu = mmu; + + /* Success. */ + gcmkFOOTER_ARG("*Mmu=0x%x", *Mmu); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (mmu != gcvNULL) + { + if (mmu->pageTableLogical != gcvNULL) + { + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(os, + mmu->pageTablePhysical, + (gctPOINTER) mmu->pageTableLogical, + mmu->pageTableSize)); + + } + + if (mmu->mtlbLogical != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeContiguous(os, + mmu->mtlbPhysical, + (gctPOINTER) mmu->mtlbLogical, + mmu->mtlbSize)); + } + + if (mmu->pageTableMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->pageTableMutex)); + } + +#ifdef __QNXNTO__ + if (mmu->nodeMutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, mmu->nodeMutex)); + } +#endif + + /* Mark the gckMMU object as unknown. */ + mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the allocates memory. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, mmu)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** _Destroy +** +** Destroy a gckMMU object. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +_Destroy( + IN gckMMU Mmu + ) +{ +#ifdef __QNXNTO__ + gcuVIDMEM_NODE_PTR node, next; +#endif + + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + +#ifdef __QNXNTO__ + /* Free all associated virtual memory. */ + for (node = Mmu->nodeList; node != gcvNULL; node = next) + { + next = node->Virtual.next; + gcmkVERIFY_OK(gckVIDMEM_Free(node)); + } +#endif + + while (Mmu->staticSTLB != gcvNULL) + { + gcsMMU_STLB_PTR pre = Mmu->staticSTLB; + Mmu->staticSTLB = pre->next; + + if (pre->physical != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + pre->physical, + pre->logical, + pre->size)); + } + + if (pre->mtlbEntryNum != 0) + { + gcmkASSERT(pre->mtlbEntryNum == 1); + *(Mmu->mtlbLogical + pre->mtlbIndex) = 0; +#if gcdMMU_TABLE_DUMP + gckOS_Print("%s(%d): clean MTLB[%d]\n", + __FUNCTION__, __LINE__, + pre->mtlbIndex); +#endif + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, pre)); + } + + if (Mmu->hardware->mmuVersion != 0) + { + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + Mmu->mtlbPhysical, + (gctPOINTER) Mmu->mtlbLogical, + Mmu->mtlbSize)); + } + + /* Free the page table. */ + gcmkVERIFY_OK( + gckOS_FreeContiguous(Mmu->os, + Mmu->pageTablePhysical, + (gctPOINTER) Mmu->pageTableLogical, + Mmu->pageTableSize)); + +#ifdef __QNXNTO__ + /* Delete the node list mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->nodeMutex)); +#endif + + /* Delete the page table mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Mark the gckMMU object as unknown. */ + Mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckMMU object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, Mmu)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ) +{ +#if gcdSHARED_PAGETABLE + gceSTATUS status; + gctPOINTER pointer; + + gcmkHEADER_ARG("Kernel=0x%08x", Kernel); + + if (sharedPageTable == gcvNULL) + { + gcmkONERROR( + gckOS_Allocate(Kernel->os, + sizeof(struct _gcsSharedPageTable), + &pointer)); + sharedPageTable = pointer; + + gcmkONERROR( + gckOS_ZeroMemory(sharedPageTable, + sizeof(struct _gcsSharedPageTable))); + + gcmkONERROR(_Construct(Kernel, MmuSize, &sharedPageTable->mmu)); + } + + *Mmu = sharedPageTable->mmu; + + sharedPageTable->hardwares[sharedPageTable->reference] = Kernel->hardware; + + sharedPageTable->reference++; + + gcmkFOOTER_ARG("sharedPageTable->reference=%lu", sharedPageTable->reference); + return gcvSTATUS_OK; + +OnError: + if (sharedPageTable) + { + if (sharedPageTable->mmu) + { + gcmkVERIFY_OK(gckMMU_Destroy(sharedPageTable->mmu)); + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Kernel->os, sharedPageTable)); + } + + gcmkFOOTER(); + return status; +#else + return _Construct(Kernel, MmuSize, Mmu); +#endif +} + +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ) +{ +#if gcdSHARED_PAGETABLE + sharedPageTable->reference--; + + if (sharedPageTable->reference == 0) + { + if (sharedPageTable->mmu) + { + gcmkVERIFY_OK(_Destroy(Mmu)); + } + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Mmu->os, sharedPageTable)); + } + + return gcvSTATUS_OK; +#else + return _Destroy(Mmu); +#endif +} + +/******************************************************************************* +** +** gckMMU_AllocatePages +** +** Allocate pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctSIZE_T PageCount +** Number of pages to allocate. +** +** OUTPUT: +** +** gctPOINTER * PageTable +** Pointer to a variable that receives the base address of the page +** table. +** +** gctUINT32 * Address +** Pointer to a variable that receives the hardware specific address. +*/ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gctUINT32 index = 0, previous = ~0U, left; + gctUINT32_PTR pageTable; + gctBOOL gotIt; + gctUINT32 address; + + gcmkHEADER_ARG("Mmu=0x%x PageCount=%lu", Mmu, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + + if (PageCount > Mmu->pageTableEntries) + { + /* Not enough pages avaiable. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->pageTableMutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Cast pointer to page table. */ + for (pageTable = Mmu->pageTableLogical, gotIt = gcvFALSE; !gotIt;) + { + /* Walk the heap list. */ + for (index = Mmu->heapList; !gotIt && (index < Mmu->pageTableEntries);) + { + /* Check the node type. */ + switch (gcmENTRY_TYPE(pageTable[index])) + { + case gcvMMU_SINGLE: + /* Single odes are valid if we only need 1 page. */ + if (PageCount == 1) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index] >> 8; + } + break; + + case gcvMMU_FREE: + /* Test if the node has enough space. */ + if (PageCount <= (pageTable[index] >> 8)) + { + gotIt = gcvTRUE; + } + else + { + /* Move to next node. */ + previous = index; + index = pageTable[index + 1]; + } + break; + + default: + gcmkFATAL("MMU table correcupted at index %u!", index); + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + + /* Test if we are out of memory. */ + if (index >= Mmu->pageTableEntries) + { + if (Mmu->freeNodes) + { + /* Time to move out the trash! */ + gcmkONERROR(_Collect(Mmu)); + } + else + { + /* Out of resources. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + } + + switch (gcmENTRY_TYPE(pageTable[index])) + { + case gcvMMU_SINGLE: + /* Unlink single node from free list. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index] >> 8)); + break; + + case gcvMMU_FREE: + /* Check how many pages will be left. */ + left = (pageTable[index] >> 8) - PageCount; + switch (left) + { + case 0: + /* The entire node is consumed, just unlink it. */ + gcmkONERROR( + _Link(Mmu, previous, pageTable[index + 1])); + break; + + case 1: + /* One page will remain. Convert the node to a single node and + ** advance the index. */ + pageTable[index] = (pageTable[index + 1] << 8) | gcvMMU_SINGLE; + index ++; + break; + + default: + /* Enough pages remain for a new node. However, we will just adjust + ** the size of the current node and advance the index. */ + pageTable[index] = (left << 8) | gcvMMU_FREE; + index += left; + break; + } + break; + } + + /* Mark node as used. */ + pageTable[index] = gcvMMU_USED; + + /* Return pointer to page table. */ + *PageTable = &pageTable[index]; + + /* Build virtual address. */ + if (Mmu->hardware->mmuVersion == 0) + { + gcmkONERROR( + gckHARDWARE_BuildVirtualAddress(Mmu->hardware, index, 0, &address)); + } + else + { + gctUINT32 masterOffset = index / gcdMMU_STLB_4K_ENTRY_NUM + + Mmu->dynamicMappingStart; + gctUINT32 slaveOffset = index % gcdMMU_STLB_4K_ENTRY_NUM; + + address = (masterOffset << gcdMMU_MTLB_SHIFT) + | (slaveOffset << gcdMMU_STLB_4K_SHIFT); + } + + if (Address != gcvNULL) + { + *Address = address; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + + /* Success. */ + gcmkFOOTER_ARG("*PageTable=0x%x *Address=%08x", + *PageTable, gcmOPT_VALUE(Address)); + return gcvSTATUS_OK; + +OnError: + + if (mutex) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->pageTableMutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckMMU_FreePages +** +** Free pages inside the page table. +** +** INPUT: +** +** gckMMU Mmu +** Pointer to an gckMMU object. +** +** gctPOINTER PageTable +** Base address of the page table to free. +** +** gctSIZE_T PageCount +** Number of pages to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ) +{ + gctUINT32_PTR pageTable; + + gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=%lu", + Mmu, PageTable, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + + /* Convert the pointer. */ + pageTable = (gctUINT32_PTR) PageTable; + +#if gcdMMU_CLEAR_VALUE + { + gctUINT32 i; + + for (i = 0; i < PageCount; ++i) + { + pageTable[i] = gcdMMU_CLEAR_VALUE; + } + } +#endif + + if (PageCount == 1) + { + /* Single page node. */ + pageTable[0] = (~((1U<<8)-1)) | gcvMMU_SINGLE; + } + else + { + /* Mark the node as free. */ + pageTable[0] = (PageCount << 8) | gcvMMU_FREE; + pageTable[1] = ~0U; + } + + /* We have free nodes. */ + Mmu->freeNodes = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckMMU_Enable( + IN gckMMU Mmu, + IN gctUINT32 PhysBaseAddr, + IN gctUINT32 PhysSize + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + +#if gcdSHARED_PAGETABLE + if (Mmu->enabled) + { + gcmkFOOTER_ARG("Status=%d", gcvSTATUS_SKIP); + return gcvSTATUS_SKIP; + } +#endif + + if (Mmu->hardware->mmuVersion == 0) + { + /* Success. */ + gcmkFOOTER_ARG("Status=%d", gcvSTATUS_SKIP); + return gcvSTATUS_SKIP; + } + else + { + if (PhysSize != 0) + { + gcmkONERROR(_FillFlatMapping( + Mmu, + PhysBaseAddr, + PhysSize + )); + } + + gcmkONERROR(_SetupDynamicSpace(Mmu)); + + gcmkONERROR( + gckHARDWARE_SetMMUv2( + Mmu->hardware, + gcvTRUE, + Mmu->mtlbLogical, + gcvMMU_MODE_4K, + (gctUINT8_PTR)Mmu->mtlbLogical + gcdMMU_MTLB_SIZE, + gcvFALSE + )); + + Mmu->enabled = gcvTRUE; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_SetPage( + IN gckMMU Mmu, + IN gctUINT32 PageAddress, + IN gctUINT32 *PageEntry + ) +{ + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL); + gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF)); + + if (Mmu->hardware->mmuVersion == 0) + { + *PageEntry = PageAddress; + } + else + { + *PageEntry = _SetPage(PageAddress); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + Node->Virtual.next = Mmu->nodeList; + Mmu->nodeList = Node; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR *iter; + + gcmkHEADER_ARG("Mmu=0x%x Node=0x%x", Mmu, Node); + + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + mutex = gcvTRUE; + + for (iter = &Mmu->nodeList; *iter; iter = &(*iter)->Virtual.next) + { + if (*iter == Node) + { + *iter = Node->Virtual.next; + break; + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckKERNEL Kernel, + IN gckMMU Mmu, + IN gctUINT32 Pid + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gcuVIDMEM_NODE_PTR curr, next; + + gcmkHEADER_ARG("Kernel=0x%x, Mmu=0x%x Pid=%u", Kernel, Mmu, Pid); + + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + gcmkONERROR(gckOS_AcquireMutex(Mmu->os, Mmu->nodeMutex, gcvINFINITE)); + acquired = gcvTRUE; + + for (curr = Mmu->nodeList; curr != gcvNULL; curr = next) + { + next = curr->Virtual.next; + + if (curr->Virtual.processID == Pid) + { + while (curr->Virtual.unlockPendings[Kernel->core] == 0 && curr->Virtual.lockeds[Kernel->core] > 0) + { + gcmkONERROR(gckVIDMEM_Unlock(Kernel, curr, gcvSURF_TYPE_UNKNOWN, gcvNULL)); + } + + gcmkVERIFY_OK(gckVIDMEM_Free(curr)); + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->nodeMutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +gceSTATUS +gckMMU_Flush( + IN gckMMU Mmu + ) +{ + gckHARDWARE hardware; +#if gcdSHARED_PAGETABLE + gctINT i; + for (i = 0; i < gcdCORE_COUNT; i++) + { +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + continue; + } +#endif + hardware = sharedPageTable->hardwares[i]; + if (hardware) + { + /* Notify cores who use this page table. */ + gcmkVERIFY_OK( + gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1)); + } + } +#else + hardware = Mmu->hardware; + gcmkVERIFY_OK( + gckOS_AtomSet(hardware->os, hardware->pageTableDirty, 1)); +#endif + + return gcvSTATUS_OK; +} + +/****************************************************************************** +****************************** T E S T C O D E ****************************** +******************************************************************************/ + diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu_vg.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu_vg.c new file mode 100644 index 0000000..a4a5e0c --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_mmu_vg.c @@ -0,0 +1,509 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#if gcdENABLE_VG + +#define _GC_OBJ_ZONE gcvZONE_MMU + +/******************************************************************************* +** +** gckVGMMU_Construct +** +** Construct a new gckVGMMU object. +** +** INPUT: +** +** gckVGKERNEL Kernel +** Pointer to an gckVGKERNEL object. +** +** gctSIZE_T MmuSize +** Number of bytes for the page table. +** +** OUTPUT: +** +** gckVGMMU * Mmu +** Pointer to a variable that receives the gckVGMMU object pointer. +*/ +gceSTATUS gckVGMMU_Construct( + IN gckVGKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckVGMMU * Mmu + ) +{ + gckOS os; + gckVGHARDWARE hardware; + gceSTATUS status; + gckVGMMU mmu; + gctUINT32 * pageTable; + gctUINT32 i; + + gcmkHEADER_ARG("Kernel=0x%x MmuSize=0x%x Mmu=0x%x", Kernel, MmuSize, Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(MmuSize > 0); + gcmkVERIFY_ARGUMENT(Mmu != gcvNULL); + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Extract the gckVGHARDWARE object pointer. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Allocate memory for the gckVGMMU object. */ + status = gckOS_Allocate(os, sizeof(struct _gckVGMMU), (gctPOINTER *) &mmu); + + if (status < 0) + { + /* Error. */ + gcmkFATAL( + "%s(%d): could not allocate gckVGMMU object.", + __FUNCTION__, __LINE__ + ); + + gcmkFOOTER(); + return status; + } + + /* Initialize the gckVGMMU object. */ + mmu->object.type = gcvOBJ_MMU; + mmu->os = os; + mmu->hardware = hardware; + + /* Create the mutex. */ + status = gckOS_CreateMutex(os, &mmu->mutex); + + if (status < 0) + { + /* Roll back. */ + mmu->object.type = gcvOBJ_UNKNOWN; + gcmkVERIFY_OK(gckOS_Free(os, mmu)); + + gcmkFOOTER(); + /* Error. */ + return status; + } + + /* Allocate the page table. */ + mmu->pageTableSize = MmuSize; + status = gckOS_AllocateContiguous(os, + gcvFALSE, + &mmu->pageTableSize, + &mmu->pageTablePhysical, + &mmu->pageTableLogical); + + if (status < 0) + { + /* Roll back. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); + + mmu->object.type = gcvOBJ_UNKNOWN; + gcmkVERIFY_OK(gckOS_Free(os, mmu)); + + /* Error. */ + gcmkFATAL( + "%s(%d): could not allocate page table.", + __FUNCTION__, __LINE__ + ); + + gcmkFOOTER(); + return status; + } + + /* Compute number of entries in page table. */ + mmu->entryCount = mmu->pageTableSize / sizeof(gctUINT32); + mmu->entry = 0; + + /* Mark the entire page table as available. */ + pageTable = (gctUINT32 *) mmu->pageTableLogical; + for (i = 0; i < mmu->entryCount; i++) + { + pageTable[i] = (gctUINT32)~0; + } + + /* Set page table address. */ + status = gckVGHARDWARE_SetMMU(hardware, mmu->pageTableLogical); + + if (status < 0) + { + /* Free the page table. */ + gcmkVERIFY_OK(gckOS_FreeContiguous(mmu->os, + mmu->pageTablePhysical, + mmu->pageTableLogical, + mmu->pageTableSize)); + + /* Roll back. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, mmu->mutex)); + + mmu->object.type = gcvOBJ_UNKNOWN; + gcmkVERIFY_OK(gckOS_Free(os, mmu)); + + /* Error. */ + gcmkFATAL( + "%s(%d): could not program page table.", + __FUNCTION__, __LINE__ + ); + + gcmkFOOTER(); + return status; + } + + /* Return the gckVGMMU object pointer. */ + *Mmu = mmu; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_MMU, + "%s(%d): %u entries at %p.(0x%08X)\n", + __FUNCTION__, __LINE__, + mmu->entryCount, + mmu->pageTableLogical, + mmu->pageTablePhysical + ); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVGMMU_Destroy +** +** Destroy a nAQMMU object. +** +** INPUT: +** +** gckVGMMU Mmu +** Pointer to an gckVGMMU object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckVGMMU_Destroy( + IN gckVGMMU Mmu + ) +{ + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + + /* Free the page table. */ + gcmkVERIFY_OK(gckOS_FreeContiguous(Mmu->os, + Mmu->pageTablePhysical, + Mmu->pageTableLogical, + Mmu->pageTableSize)); + + /* Roll back. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Mmu->os, Mmu->mutex)); + + /* Mark the gckVGMMU object as unknown. */ + Mmu->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVGMMU object. */ + gcmkVERIFY_OK(gckOS_Free(Mmu->os, Mmu)); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVGMMU_AllocatePages +** +** Allocate pages inside the page table. +** +** INPUT: +** +** gckVGMMU Mmu +** Pointer to an gckVGMMU object. +** +** gctSIZE_T PageCount +** Number of pages to allocate. +** +** OUTPUT: +** +** gctPOINTER * PageTable +** Pointer to a variable that receives the base address of the page +** table. +** +** gctUINT32 * Address +** Pointer to a variable that receives the hardware specific address. +*/ +gceSTATUS gckVGMMU_AllocatePages( + IN gckVGMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctUINT32 tail, index, i; + gctUINT32 * table; + gctBOOL allocated = gcvFALSE; + + gcmkHEADER_ARG("Mmu=0x%x PageCount=0x%x PageTable=0x%x Address=0x%x", + Mmu, PageCount, PageTable, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_MMU, + "%s(%d): %u pages.\n", + __FUNCTION__, __LINE__, + PageCount + ); + + if (PageCount > Mmu->entryCount) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_MMU, + "%s(%d): page table too small for %u pages.\n", + __FUNCTION__, __LINE__, + PageCount + ); + + gcmkFOOTER_NO(); + /* Not enough pages avaiable. */ + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Grab the mutex. */ + status = gckOS_AcquireMutex(Mmu->os, Mmu->mutex, gcvINFINITE); + + if (status < 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_MMU, + "%s(%d): could not acquire mutex.\n" + ,__FUNCTION__, __LINE__ + ); + + gcmkFOOTER(); + /* Error. */ + return status; + } + + /* Compute the tail for this allocation. */ + tail = Mmu->entryCount - PageCount; + + /* Walk all entries until we find enough slots. */ + for (index = Mmu->entry; index <= tail;) + { + /* Access page table. */ + table = (gctUINT32 *) Mmu->pageTableLogical + index; + + /* See if all slots are available. */ + for (i = 0; i < PageCount; i++, table++) + { + if (*table != ~0) + { + /* Start from next slot. */ + index += i + 1; + break; + } + } + + if (i == PageCount) + { + /* Bail out if we have enough page entries. */ + allocated = gcvTRUE; + break; + } + } + + if (!allocated) + { + /* Flush the MMU. */ + status = gckVGHARDWARE_FlushMMU(Mmu->hardware); + + if (status >= 0) + { + /* Walk all entries until we find enough slots. */ + for (index = 0; index <= tail;) + { + /* Access page table. */ + table = (gctUINT32 *) Mmu->pageTableLogical + index; + + /* See if all slots are available. */ + for (i = 0; i < PageCount; i++, table++) + { + if (*table != ~0) + { + /* Start from next slot. */ + index += i + 1; + break; + } + } + + if (i == PageCount) + { + /* Bail out if we have enough page entries. */ + allocated = gcvTRUE; + break; + } + } + } + } + + if (!allocated && (status >= 0)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_MMU, + "%s(%d): not enough free pages for %u pages.\n", + __FUNCTION__, __LINE__, + PageCount + ); + + /* Not enough empty slots available. */ + status = gcvSTATUS_OUT_OF_RESOURCES; + } + + if (status >= 0) + { + /* Build virtual address. */ + status = gckVGHARDWARE_BuildVirtualAddress(Mmu->hardware, + index, + 0, + Address); + + if (status >= 0) + { + /* Update current entry into page table. */ + Mmu->entry = index + PageCount; + + /* Return pointer to page table. */ + *PageTable = (gctUINT32 *) Mmu->pageTableLogical + index; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_MMU, + "%s(%d): allocated %u pages at index %u (0x%08X) @ %p.\n", + __FUNCTION__, __LINE__, + PageCount, + index, + *Address, + *PageTable + ); + } + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Mmu->os, Mmu->mutex)); + gcmkFOOTER(); + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckVGMMU_FreePages +** +** Free pages inside the page table. +** +** INPUT: +** +** gckVGMMU Mmu +** Pointer to an gckVGMMU object. +** +** gctPOINTER PageTable +** Base address of the page table to free. +** +** gctSIZE_T PageCount +** Number of pages to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckVGMMU_FreePages( + IN gckVGMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ) +{ + gctUINT32 * table; + + gcmkHEADER_ARG("Mmu=0x%x PageTable=0x%x PageCount=0x%x", + Mmu, PageTable, PageCount); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_MMU, + "%s(%d): freeing %u pages at index %u @ %p.\n", + __FUNCTION__, __LINE__, + PageCount, + ((gctUINT32 *) PageTable - (gctUINT32 *) Mmu->pageTableLogical), + PageTable + ); + + /* Convert pointer. */ + table = (gctUINT32 *) PageTable; + + /* Mark the page table entries as available. */ + while (PageCount-- > 0) + { + *table++ = (gctUINT32)~0; + } + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckVGMMU_SetPage( + IN gckVGMMU Mmu, + IN gctUINT32 PageAddress, + IN gctUINT32 *PageEntry + ) +{ + gcmkHEADER_ARG("Mmu=0x%x", Mmu); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Mmu, gcvOBJ_MMU); + gcmkVERIFY_ARGUMENT(PageEntry != gcvNULL); + gcmkVERIFY_ARGUMENT(!(PageAddress & 0xFFF)); + + *PageEntry = PageAddress; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#endif /* gcdENABLE_VG */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_precomp.h b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_precomp.h new file mode 100644 index 0000000..004e6bd --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_precomp.h @@ -0,0 +1,31 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_precomp_h_ +#define __gc_hal_kernel_precomp_h_ + +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" + +#endif /* __gc_hal_kernel_precomp_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.c new file mode 100644 index 0000000..5c1d809 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.c @@ -0,0 +1,805 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#if gcdENABLE_VG + +#define _GC_OBJ_ZONE gcvZONE_VG + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_Construct +** +** Construct a new gckKERNEL object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN gctPOINTER Context +** Pointer to a driver defined context. +** +** OUTPUT: +** +** gckKERNEL * Kernel +** Pointer to a variable that will hold the pointer to the gckKERNEL +** object. +*/ +gceSTATUS gckVGKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + IN gckKERNEL inKernel, + OUT gckVGKERNEL * Kernel + ) +{ + gceSTATUS status; + gckVGKERNEL kernel = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x Context=0x%x", Os, Context); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); + + do + { + /* Allocate the gckKERNEL object. */ + gcmkERR_BREAK(gckOS_Allocate( + Os, + sizeof(struct _gckVGKERNEL), + (gctPOINTER *) &kernel + )); + + /* Initialize the gckKERNEL object. */ + kernel->object.type = gcvOBJ_KERNEL; + kernel->os = Os; + kernel->context = Context; + kernel->hardware = gcvNULL; + kernel->interrupt = gcvNULL; + kernel->command = gcvNULL; + kernel->mmu = gcvNULL; + kernel->kernel = inKernel; + + /* Construct the gckVGHARDWARE object. */ + gcmkERR_BREAK(gckVGHARDWARE_Construct( + Os, &kernel->hardware + )); + + /* Set pointer to gckKERNEL object in gckVGHARDWARE object. */ + kernel->hardware->kernel = kernel; + + /* Construct the gckVGINTERRUPT object. */ + gcmkERR_BREAK(gckVGINTERRUPT_Construct( + kernel, &kernel->interrupt + )); + + /* Construct the gckVGCOMMAND object. */ + gcmkERR_BREAK(gckVGCOMMAND_Construct( + kernel, gcmKB2BYTES(8), gcmKB2BYTES(2), &kernel->command + )); + + /* Construct the gckVGMMU object. */ + gcmkERR_BREAK(gckVGMMU_Construct( + kernel, gcmKB2BYTES(32), &kernel->mmu + )); + + /* Return pointer to the gckKERNEL object. */ + *Kernel = kernel; + + gcmkFOOTER_ARG("*Kernel=0x%x", *Kernel); + /* Success. */ + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Roll back. */ + if (kernel != gcvNULL) + { + if (kernel->mmu != gcvNULL) + { + gcmkVERIFY_OK(gckVGMMU_Destroy(kernel->mmu)); + } + + if (kernel->command != gcvNULL) + { + gcmkVERIFY_OK(gckVGCOMMAND_Destroy(kernel->command)); + } + + if (kernel->interrupt != gcvNULL) + { + gcmkVERIFY_OK(gckVGINTERRUPT_Destroy(kernel->interrupt)); + } + + if (kernel->hardware != gcvNULL) + { + gcmkVERIFY_OK(gckVGHARDWARE_Destroy(kernel->hardware)); + } + + gcmkVERIFY_OK(gckOS_Free(Os, kernel)); + } + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Destroy +** +** Destroy an gckKERNEL object. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckVGKERNEL_Destroy( + IN gckVGKERNEL Kernel + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=0x%x", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + do + { + /* Destroy the gckVGMMU object. */ + if (Kernel->mmu != gcvNULL) + { + gcmkERR_BREAK(gckVGMMU_Destroy(Kernel->mmu)); + Kernel->mmu = gcvNULL; + } + + /* Destroy the gckVGCOMMAND object. */ + if (Kernel->command != gcvNULL) + { + gcmkERR_BREAK(gckVGCOMMAND_Destroy(Kernel->command)); + Kernel->command = gcvNULL; + } + + /* Destroy the gckVGINTERRUPT object. */ + if (Kernel->interrupt != gcvNULL) + { + gcmkERR_BREAK(gckVGINTERRUPT_Destroy(Kernel->interrupt)); + Kernel->interrupt = gcvNULL; + } + + /* Destroy the gckVGHARDWARE object. */ + if (Kernel->hardware != gcvNULL) + { + gcmkERR_BREAK(gckVGHARDWARE_Destroy(Kernel->hardware)); + Kernel->hardware = gcvNULL; + } + + /* Mark the gckKERNEL object as unknown. */ + Kernel->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckKERNEL object. */ + gcmkERR_BREAK(gckOS_Free(Kernel->os, Kernel)); + } + while (gcvFALSE); + + gcmkFOOTER(); + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckKERNEL_AllocateLinearMemory +** +** Function walks all required memory pools and allocates the requested +** amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcePOOL * Pool +** Pointer the desired memory pool. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** gctSIZE_T Alignment +** Required buffer alignment. +** +** gceSURF_TYPE Type +** Surface type. +** +** OUTPUT: +** +** gcePOOL * Pool +** Pointer to the actual pool where the memory was allocated. +** +** gcuVIDMEM_NODE_PTR * Node +** Allocated node. +*/ +gceSTATUS +gckKERNEL_AllocateLinearMemory( + IN gckKERNEL Kernel, + IN OUT gcePOOL * Pool, + IN gctSIZE_T Bytes, + IN gctSIZE_T Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gcePOOL pool; + gceSTATUS status; + gckVIDMEM videoMemory; + + /* Get initial pool. */ + switch (pool = *Pool) + { + case gcvPOOL_DEFAULT: + case gcvPOOL_LOCAL: + pool = gcvPOOL_LOCAL_INTERNAL; + break; + + case gcvPOOL_UNIFIED: + pool = gcvPOOL_SYSTEM; + break; + + default: + break; + } + + do + { + /* Verify the number of bytes to allocate. */ + if (Bytes == 0) + { + status = gcvSTATUS_INVALID_ARGUMENT; + break; + } + + if (pool == gcvPOOL_VIRTUAL) + { + /* Create a gcuVIDMEM_NODE for virtual memory. */ + gcmkERR_BREAK(gckVIDMEM_ConstructVirtual(Kernel, gcvFALSE, Bytes, Node)); + + /* Success. */ + break; + } + + else + { + /* Get pointer to gckVIDMEM object for pool. */ + status = gckKERNEL_GetVideoMemoryPool(Kernel, pool, &videoMemory); + + if (status == gcvSTATUS_OK) + { + /* Allocate memory. */ + status = gckVIDMEM_AllocateLinear(videoMemory, + Bytes, + Alignment, + Type, + Node); + + if (status == gcvSTATUS_OK) + { + /* Memory allocated. */ + break; + } + } + } + + if (pool == gcvPOOL_LOCAL_INTERNAL) + { + /* Advance to external memory. */ + pool = gcvPOOL_LOCAL_EXTERNAL; + } + else if (pool == gcvPOOL_LOCAL_EXTERNAL) + { + /* Advance to contiguous system memory. */ + pool = gcvPOOL_SYSTEM; + } + else if (pool == gcvPOOL_SYSTEM) + { + /* Advance to virtual memory. */ + pool = gcvPOOL_VIRTUAL; + } + else + { + /* Out of pools. */ + break; + } + } + /* Loop only for multiple selection pools. */ + while ((*Pool == gcvPOOL_DEFAULT) + || (*Pool == gcvPOOL_LOCAL) + || (*Pool == gcvPOOL_UNIFIED) + ); + + if (gcmIS_SUCCESS(status)) + { + /* Return pool used for allocation. */ + *Pool = pool; + } + + /* Return status. */ + return status; +} + +/******************************************************************************* +** +** gckKERNEL_Dispatch +** +** Dispatch a command received from the user HAL layer. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that defines the command to +** be dispatched. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to a gcsHAL_INTERFACE structure that receives any data to be +** returned. +*/ +gceSTATUS gckVGKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT gcsHAL_INTERFACE * Interface + ) +{ + gceSTATUS status; + gcsHAL_INTERFACE * kernelInterface = Interface; + gcuVIDMEM_NODE_PTR node; + gctUINT32 processID; + + 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: + /* Allocate non-paged memory. */ + gcmkERR_BREAK(gckOS_AllocateContiguous( + Kernel->os, + gcvTRUE, + &kernelInterface->u.AllocateNonPagedMemory.bytes, + &kernelInterface->u.AllocateNonPagedMemory.physical, + &kernelInterface->u.AllocateNonPagedMemory.logical + )); + break; + + case gcvHAL_FREE_NON_PAGED_MEMORY: + /* Free non-paged memory. */ + gcmkERR_BREAK(gckOS_FreeNonPagedMemory( + Kernel->os, + kernelInterface->u.AllocateNonPagedMemory.bytes, + kernelInterface->u.AllocateNonPagedMemory.physical, + kernelInterface->u.AllocateNonPagedMemory.logical + )); + break; + + case gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY: + /* Allocate contiguous memory. */ + gcmkERR_BREAK(gckOS_AllocateContiguous( + Kernel->os, + gcvTRUE, + &kernelInterface->u.AllocateNonPagedMemory.bytes, + &kernelInterface->u.AllocateNonPagedMemory.physical, + &kernelInterface->u.AllocateNonPagedMemory.logical + )); + break; + + case gcvHAL_FREE_CONTIGUOUS_MEMORY: + /* Free contiguous memory. */ + gcmkERR_BREAK(gckOS_FreeContiguous( + Kernel->os, + kernelInterface->u.AllocateNonPagedMemory.physical, + kernelInterface->u.AllocateNonPagedMemory.logical, + kernelInterface->u.AllocateNonPagedMemory.bytes + )); + 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, + &kernelInterface->u.AllocateVideoMemory.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, + &kernelInterface->u.AllocateLinearVideoMemory.node + )); + break; + + case gcvHAL_FREE_VIDEO_MEMORY: +#ifdef __QNXNTO__ + /* Unmap the video memory */ + node = Interface->u.FreeVideoMemory.node; + + 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( + Interface->u.FreeVideoMemory.node + )); + break; + + case gcvHAL_MAP_MEMORY: + /* Map memory. */ + gcmkERR_BREAK(gckKERNEL_MapMemory( + Kernel, + kernelInterface->u.MapMemory.physical, + kernelInterface->u.MapMemory.bytes, + &kernelInterface->u.MapMemory.logical + )); + break; + + case gcvHAL_UNMAP_MEMORY: + /* Unmap memory. */ + gcmkERR_BREAK(gckKERNEL_UnmapMemory( + Kernel, + kernelInterface->u.MapMemory.physical, + kernelInterface->u.MapMemory.bytes, + kernelInterface->u.MapMemory.logical + )); + break; + + case gcvHAL_MAP_USER_MEMORY: + /* Map user memory to DMA. */ + gcmkERR_BREAK(gckOS_MapUserMemory( + Kernel->os, + kernelInterface->u.MapUserMemory.memory, + kernelInterface->u.MapUserMemory.size, + &kernelInterface->u.MapUserMemory.info, + &kernelInterface->u.MapUserMemory.address + )); + break; + + case gcvHAL_UNMAP_USER_MEMORY: + /* Unmap user memory. */ + gcmkERR_BREAK(gckOS_UnmapUserMemory( + Kernel->os, + kernelInterface->u.UnmapUserMemory.memory, + kernelInterface->u.UnmapUserMemory.size, + kernelInterface->u.UnmapUserMemory.info, + kernelInterface->u.UnmapUserMemory.address + )); + break; + case gcvHAL_LOCK_VIDEO_MEMORY: + /* Lock video memory. */ + gcmkERR_BREAK( + gckVIDMEM_Lock(Kernel, + Interface->u.LockVideoMemory.node, + gcvFALSE, + &Interface->u.LockVideoMemory.address)); + + 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, + processID, + node->VidMem.bytes, + &node->VidMem.logical)); + } + + Interface->u.LockVideoMemory.memory = node->VidMem.logical; +#else + gcmkERR_BREAK( + gckKERNEL_MapVideoMemoryEx(Kernel, + gcvCORE_VG, + FromUser, + Interface->u.LockVideoMemory.address, + &Interface->u.LockVideoMemory.memory)); +#endif + } + else + { + 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; + +#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 + 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, + kernelInterface->u.VGCommit.context, + kernelInterface->u.VGCommit.queue, + kernelInterface->u.VGCommit.entryCount, + 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; +} + +/******************************************************************************* +** +** gckKERNEL_QueryCommandBuffer +** +** Query command buffer attributes. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckVGHARDWARE object. +** +** OUTPUT: +** +** gcsCOMMAND_BUFFER_INFO_PTR Information +** Pointer to the information structure to receive buffer attributes. +*/ +gceSTATUS +gckKERNEL_QueryCommandBuffer( + IN gckKERNEL Kernel, + OUT gcsCOMMAND_BUFFER_INFO_PTR Information + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=0x%x *Pool=0x%x", + Kernel, Information); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Get the information. */ + status = gckVGCOMMAND_QueryCommandBuffer(Kernel->vg->command, Information); + + gcmkFOOTER(); + /* Return status. */ + return status; +} + +#endif /* gcdENABLE_VG */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.h b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.h new file mode 100644 index 0000000..04fccf4 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_vg.h @@ -0,0 +1,90 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + + + +#ifndef __gc_hal_kernel_vg_h_ +#define __gc_hal_kernel_vg_h_ + +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel_hardware.h" + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ + + +/* gckKERNEL object. */ +struct _gckVGKERNEL +{ + /* Object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckVGHARDWARE hardware; + + /* Pointer to gckINTERRUPT object. */ + gckVGINTERRUPT interrupt; + + /* Pointer to gckCOMMAND object. */ + gckVGCOMMAND command; + + /* Pointer to context. */ + gctPOINTER context; + + /* Pointer to gckMMU object. */ + gckVGMMU mmu; + + gckKERNEL kernel; +}; + +/* gckMMU object. */ +struct _gckVGMMU +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to gckOS object. */ + gckOS os; + + /* Pointer to gckHARDWARE object. */ + gckVGHARDWARE hardware; + + /* The page table mutex. */ + gctPOINTER mutex; + + /* Page table information. */ + gctSIZE_T pageTableSize; + gctPHYS_ADDR pageTablePhysical; + gctPOINTER pageTableLogical; + + /* Allocation index. */ + gctUINT32 entryCount; + gctUINT32 entry; +}; + +#endif /* __gc_hal_kernel_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/gc_hal_kernel_video_memory.c b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_video_memory.c new file mode 100644 index 0000000..9fd50e8 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/gc_hal_kernel_video_memory.c @@ -0,0 +1,2187 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_precomp.h" + +#define _GC_OBJ_ZONE gcvZONE_VIDMEM + +/******************************************************************************\ +******************************* Private Functions ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** _Split +** +** Split a node on the required byte boundary. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the node to split. +** +** gctSIZE_T Bytes +** Number of bytes to keep in the node. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gctBOOL +** gcvTRUE if the node was split successfully, or gcvFALSE if there is an +** error. +** +*/ +static gctBOOL +_Split( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctSIZE_T Bytes + ) +{ + gcuVIDMEM_NODE_PTR node; + gctPOINTER pointer = gcvNULL; + + /* Make sure the byte boundary makes sense. */ + if ((Bytes <= 0) || (Bytes > Node->VidMem.bytes)) + { + return gcvFALSE; + } + + /* Allocate a new gcuVIDMEM_NODE object. */ + if (gcmIS_ERROR(gckOS_Allocate(Os, + gcmSIZEOF(gcuVIDMEM_NODE), + &pointer))) + { + /* Error. */ + return gcvFALSE; + } + + node = pointer; + + /* Initialize gcuVIDMEM_NODE structure. */ + node->VidMem.offset = Node->VidMem.offset + Bytes; + node->VidMem.bytes = Node->VidMem.bytes - Bytes; + node->VidMem.alignment = 0; + node->VidMem.locked = 0; + node->VidMem.memory = Node->VidMem.memory; + node->VidMem.pool = Node->VidMem.pool; + node->VidMem.physical = Node->VidMem.physical; +#ifdef __QNXNTO__ +#if gcdUSE_VIDMEM_PER_PID + gcmkASSERT(Node->VidMem.physical != 0); + gcmkASSERT(Node->VidMem.logical != gcvNULL); + node->VidMem.processID = Node->VidMem.processID; + node->VidMem.physical = Node->VidMem.physical + Bytes; + node->VidMem.logical = Node->VidMem.logical + Bytes; +#else + node->VidMem.processID = 0; + node->VidMem.logical = gcvNULL; +#endif +#endif + + /* Insert node behind specified node. */ + node->VidMem.next = Node->VidMem.next; + node->VidMem.prev = Node; + Node->VidMem.next = node->VidMem.next->VidMem.prev = node; + + /* Insert free node behind specified node. */ + node->VidMem.nextFree = Node->VidMem.nextFree; + node->VidMem.prevFree = Node; + Node->VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node; + + /* Adjust size of specified node. */ + Node->VidMem.bytes = Bytes; + + /* Success. */ + return gcvTRUE; +} + +/******************************************************************************* +** +** _Merge +** +** Merge two adjacent nodes together. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to the first of the two nodes to merge. +** +** OUTPUT: +** +** Nothing. +** +*/ +static gceSTATUS +_Merge( + IN gckOS Os, + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gcuVIDMEM_NODE_PTR node; + gceSTATUS status; + + /* Save pointer to next node. */ + node = Node->VidMem.next; +#if gcdUSE_VIDMEM_PER_PID + /* Check if the nodes are adjacent physically. */ + if ( ((Node->VidMem.physical + Node->VidMem.bytes) != node->VidMem.physical) || + ((Node->VidMem.logical + Node->VidMem.bytes) != node->VidMem.logical) ) + { + /* Can't merge. */ + return gcvSTATUS_OK; + } +#else + + /* This is a good time to make sure the heap is not corrupted. */ + if (Node->VidMem.offset + Node->VidMem.bytes != node->VidMem.offset) + { + /* Corrupted heap. */ + gcmkASSERT( + Node->VidMem.offset + Node->VidMem.bytes == node->VidMem.offset); + return gcvSTATUS_HEAP_CORRUPTED; + } +#endif + + /* Adjust byte count. */ + Node->VidMem.bytes += node->VidMem.bytes; + + /* Unlink next node from linked list. */ + Node->VidMem.next = node->VidMem.next; + Node->VidMem.nextFree = node->VidMem.nextFree; + + Node->VidMem.next->VidMem.prev = + Node->VidMem.nextFree->VidMem.prevFree = Node; + + /* Free next node. */ + status = gcmkOS_SAFE_FREE(Os, node); + return status; +} + +/******************************************************************************\ +******************************* gckVIDMEM API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckVIDMEM_ConstructVirtual +** +** Construct a new gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctSIZE_T Bytes +** Number of byte to allocate. +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that receives the gcuVIDMEM_NODE union pointer. +*/ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gckOS os; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node = gcvNULL; + gctPOINTER pointer = gcvNULL; + gctINT i; + + gcmkHEADER_ARG("Kernel=0x%x Contiguous=%d Bytes=%lu", Kernel, Contiguous, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + + /* Extract the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Allocate an gcuVIDMEM_NODE union. */ + gcmkONERROR(gckOS_Allocate(os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer)); + + node = pointer; + + /* Initialize gcuVIDMEM_NODE union for virtual memory. */ + node->Virtual.kernel = Kernel; + node->Virtual.contiguous = Contiguous; + node->Virtual.logical = gcvNULL; + + for (i = 0; i < gcdCORE_COUNT; i++) + { + node->Virtual.lockeds[i] = 0; + node->Virtual.pageTables[i] = gcvNULL; + node->Virtual.lockKernels[i] = gcvNULL; + } + + node->Virtual.mutex = gcvNULL; + + gcmkONERROR(gckOS_GetProcessID(&node->Virtual.processID)); + +#ifdef __QNXNTO__ + node->Virtual.next = gcvNULL; + node->Virtual.freePending = gcvFALSE; + for (i = 0; i < gcdCORE_COUNT; i++) + { + node->Virtual.unlockPendings[i] = gcvFALSE; + } +#endif + + node->Virtual.freed = gcvFALSE; + + gcmkONERROR(gckOS_ZeroMemory(&node->Virtual.sharedInfo, gcmSIZEOF(gcsVIDMEM_NODE_SHARED_INFO))); + + /* Create the mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &node->Virtual.mutex)); + + /* Allocate the virtual memory. */ + gcmkONERROR( + gckOS_AllocatePagedMemoryEx(os, + node->Virtual.contiguous, + node->Virtual.bytes = Bytes, + &node->Virtual.physical)); + +#ifdef __QNXNTO__ + /* Register. */ + gckMMU_InsertNode(Kernel->mmu, node); +#endif + + /* Return pointer to the gcuVIDMEM_NODE union. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Created virtual node 0x%x for %u bytes @ 0x%x", + node, Bytes, node->Virtual.physical); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (node != gcvNULL) + { + if (node->Virtual.mutex != gcvNULL) + { + /* Destroy the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, node->Virtual.mutex)); + } + + /* Free the structure. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, node)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_DestroyVirtual +** +** Destroy an gcuVIDMEM_NODE union for virtual memory. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gckOS os; + gctINT i; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extact the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + +#ifdef __QNXNTO__ + /* Unregister. */ + gcmkVERIFY_OK( + gckMMU_RemoveNode(Node->Virtual.kernel->mmu, Node)); +#endif + + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(os, Node->Virtual.mutex)); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (Node->Virtual.pageTables[i] != gcvNULL) + { +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + /* Free the pages. */ + gcmkVERIFY_OK(gckVGMMU_FreePages(Node->Virtual.lockKernels[i]->vg->mmu, + Node->Virtual.pageTables[i], + Node->Virtual.pageCount)); + } + else +#endif + { + /* Free the pages. */ + gcmkVERIFY_OK(gckMMU_FreePages(Node->Virtual.lockKernels[i]->mmu, + Node->Virtual.pageTables[i], + Node->Virtual.pageCount)); + } + } + } + + /* Delete the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(os, Node)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Construct +** +** Construct a new gckVIDMEM object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 BaseAddress +** Base address for the video memory heap. +** +** gctSIZE_T Bytes +** Number of bytes in the video memory heap. +** +** gctSIZE_T Threshold +** Minimum number of bytes beyond am allocation before the node is +** split. Can be used as a minimum alignment requirement. +** +** gctSIZE_T BankSize +** Number of bytes per physical memory bank. Used by bank +** optimization. +** +** OUTPUT: +** +** gckVIDMEM * Memory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object. +*/ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T BankSize, + OUT gckVIDMEM * Memory + ) +{ + gckVIDMEM memory = gcvNULL; + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctINT i, banks = 0; + gctPOINTER pointer = gcvNULL; + + gcmkHEADER_ARG("Os=0x%x BaseAddress=%08x Bytes=%lu Threshold=%lu " + "BankSize=%lu", + Os, BaseAddress, Bytes, Threshold, BankSize); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Allocate the gckVIDMEM object. */ + gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(struct _gckVIDMEM), &pointer)); + + memory = pointer; + + /* Initialize the gckVIDMEM object. */ + memory->object.type = gcvOBJ_VIDMEM; + memory->os = Os; + + /* Set video memory heap information. */ + memory->baseAddress = BaseAddress; + memory->bytes = Bytes; + memory->freeBytes = Bytes; + memory->threshold = Threshold; + memory->mutex = gcvNULL; +#if gcdUSE_VIDMEM_PER_PID + gcmkONERROR(gckOS_GetProcessID(&memory->pid)); +#endif + + BaseAddress = 0; + + /* Walk all possible banks. */ + for (i = 0; i < gcmCOUNTOF(memory->sentinel); ++i) + { + gctSIZE_T bytes; + + if (BankSize == 0) + { + /* Use all bytes for the first bank. */ + bytes = Bytes; + } + else + { + /* Compute number of bytes for this bank. */ + bytes = gcmALIGN(BaseAddress + 1, BankSize) - BaseAddress; + + if (bytes > Bytes) + { + /* Make sure we don't exceed the total number of bytes. */ + bytes = Bytes; + } + } + + if (bytes == 0) + { + /* Mark heap is not used. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = gcvNULL; + continue; + } + + /* Allocate one gcuVIDMEM_NODE union. */ + gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(gcuVIDMEM_NODE), &pointer)); + + node = pointer; + + /* Initialize gcuVIDMEM_NODE union. */ + node->VidMem.memory = memory; + + node->VidMem.next = + node->VidMem.prev = + node->VidMem.nextFree = + node->VidMem.prevFree = &memory->sentinel[i]; + + node->VidMem.offset = BaseAddress; + node->VidMem.bytes = bytes; + node->VidMem.alignment = 0; + node->VidMem.physical = 0; + node->VidMem.pool = gcvPOOL_UNKNOWN; + + node->VidMem.locked = 0; + + gcmkONERROR(gckOS_ZeroMemory(&node->VidMem.sharedInfo, gcmSIZEOF(gcsVIDMEM_NODE_SHARED_INFO))); + +#ifdef __QNXNTO__ +#if gcdUSE_VIDMEM_PER_PID + node->VidMem.processID = memory->pid; + node->VidMem.physical = memory->baseAddress + BaseAddress; + gcmkONERROR(gckOS_GetLogicalAddressProcess(Os, + node->VidMem.processID, + node->VidMem.physical, + &node->VidMem.logical)); +#else + node->VidMem.processID = 0; + node->VidMem.logical = gcvNULL; +#endif +#endif + + /* Initialize the linked list of nodes. */ + memory->sentinel[i].VidMem.next = + memory->sentinel[i].VidMem.prev = + memory->sentinel[i].VidMem.nextFree = + memory->sentinel[i].VidMem.prevFree = node; + + /* Mark sentinel. */ + memory->sentinel[i].VidMem.bytes = 0; + + /* Adjust address for next bank. */ + BaseAddress += bytes; + Bytes -= bytes; + banks ++; + } + + /* Assign all the bank mappings. */ + memory->mapping[gcvSURF_RENDER_TARGET] = banks - 1; + memory->mapping[gcvSURF_BITMAP] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_DEPTH] = banks - 1; + memory->mapping[gcvSURF_HIERARCHICAL_DEPTH] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TEXTURE] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_VERTEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_INDEX] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TILE_STATUS] = banks - 1; + if (banks > 1) --banks; + memory->mapping[gcvSURF_TYPE_UNKNOWN] = 0; + +#if gcdENABLE_VG + memory->mapping[gcvSURF_IMAGE] = 0; + memory->mapping[gcvSURF_MASK] = 0; + memory->mapping[gcvSURF_SCISSOR] = 0; +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] INDEX: bank %d", + memory->mapping[gcvSURF_INDEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] VERTEX: bank %d", + memory->mapping[gcvSURF_VERTEX]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TEXTURE: bank %d", + memory->mapping[gcvSURF_TEXTURE]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] RENDER_TARGET: bank %d", + memory->mapping[gcvSURF_RENDER_TARGET]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] DEPTH: bank %d", + memory->mapping[gcvSURF_DEPTH]); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "[GALCORE] TILE_STATUS: bank %d", + memory->mapping[gcvSURF_TILE_STATUS]); + + /* Allocate the mutex. */ + gcmkONERROR(gckOS_CreateMutex(Os, &memory->mutex)); + + /* Return pointer to the gckVIDMEM object. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%x", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + if (memory != gcvNULL) + { + if (memory->mutex != gcvNULL) + { + /* Delete the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, memory->mutex)); + } + + for (i = 0; i < banks; ++i) + { + /* Free the heap. */ + gcmkASSERT(memory->sentinel[i].VidMem.next != gcvNULL); + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory->sentinel[i].VidMem.next)); + } + + /* Free the object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, memory)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Destroy +** +** Destroy an gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ) +{ + gcuVIDMEM_NODE_PTR node, next; + gctINT i; + + gcmkHEADER_ARG("Memory=0x%x", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = next) + { + /* Save pointer to the next node. */ + next = node->VidMem.next; + + /* Free the node. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, node)); + } + } + + /* Free the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Memory->os, Memory->mutex)); + + /* Mark the object as unknown. */ + Memory->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckVIDMEM object. */ + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Memory->os, Memory)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckVIDMEM_Allocate +** +** Allocate rectangular memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctUINT Width +** Width of rectangle to allocate. Make sure the width is properly +** aligned. +** +** gctUINT Height +** Height of rectangle to allocate. Make sure the height is properly +** aligned. +** +** gctUINT Depth +** Depth of rectangle to allocate. This equals to the number of +** rectangles to allocate contiguously (i.e., for cubic maps and volume +** textures). +** +** gctUINT BytesPerPixel +** Number of bytes per pixel. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gctSIZE_T bytes; + gceSTATUS status; + + gcmkHEADER_ARG("Memory=0x%x Width=%u Height=%u Depth=%u BytesPerPixel=%u " + "Alignment=%u Type=%d", + Memory, Width, Height, Depth, BytesPerPixel, Alignment, + Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Width > 0); + gcmkVERIFY_ARGUMENT(Height > 0); + gcmkVERIFY_ARGUMENT(Depth > 0); + gcmkVERIFY_ARGUMENT(BytesPerPixel > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + + /* Compute linear size. */ + bytes = Width * Height * Depth * BytesPerPixel; + + /* Allocate through linear function. */ + gcmkONERROR( + gckVIDMEM_AllocateLinear(Memory, bytes, Alignment, Type, Node)); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdENABLE_BANK_ALIGNMENT + +#if !gcdBANK_BIT_START +#error gcdBANK_BIT_START not defined. +#endif + +#if !gcdBANK_BIT_END +#error gcdBANK_BIT_END not defined. +#endif +/******************************************************************************* +** _GetSurfaceBankAlignment +** +** Return the required offset alignment required to the make BaseAddress +** aligned properly. +** +** INPUT: +** +** gckOS Os +** Pointer to gcoOS object. +** +** gceSURF_TYPE Type +** Type of allocation. +** +** gctUINT32 BaseAddress +** Base address of current video memory node. +** +** OUTPUT: +** +** gctUINT32_PTR AlignmentOffset +** Pointer to a variable that will hold the number of bytes to skip in +** the current video memory node in order to make the alignment bank +** aligned. +*/ +static gceSTATUS +_GetSurfaceBankAlignment( + IN gceSURF_TYPE Type, + IN gctUINT32 BaseAddress, + OUT gctUINT32_PTR AlignmentOffset + ) +{ + gctUINT32 bank; + /* To retrieve the bank. */ + static const gctUINT32 bankMask = (0xFFFFFFFF << gcdBANK_BIT_START) + ^ (0xFFFFFFFF << (gcdBANK_BIT_END + 1)); + + /* To retrieve the bank and all the lower bytes. */ + static const gctUINT32 byteMask = ~(0xFFFFFFFF << (gcdBANK_BIT_END + 1)); + + gcmkHEADER_ARG("Type=%d BaseAddress=0x%x ", Type, BaseAddress); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(AlignmentOffset != gcvNULL); + + switch (Type) + { + case gcvSURF_RENDER_TARGET: + bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START); + + /* Align to the first bank. */ + *AlignmentOffset = (bank == 0) ? + 0 : + ((1 << (gcdBANK_BIT_END + 1)) + 0) - (BaseAddress & byteMask); + break; + + case gcvSURF_DEPTH: + bank = (BaseAddress & bankMask) >> (gcdBANK_BIT_START); + + /* Align to the third bank. */ + *AlignmentOffset = (bank == 2) ? + 0 : + ((1 << (gcdBANK_BIT_END + 1)) + (2 << gcdBANK_BIT_START)) - (BaseAddress & byteMask); + + /* Add a channel offset at the channel bit. */ + *AlignmentOffset += (1 << gcdBANK_CHANNEL_BIT); + break; + + default: + /* no alignment needed. */ + *AlignmentOffset = 0; + } + + /* Return the status. */ + gcmkFOOTER_ARG("*AlignmentOffset=%u", *AlignmentOffset); + return gcvSTATUS_OK; +} +#endif + +static gcuVIDMEM_NODE_PTR +_FindNode( + IN gckVIDMEM Memory, + IN gctINT Bank, + IN gctSIZE_T Bytes, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Alignment + ) +{ + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + +#if gcdENABLE_BANK_ALIGNMENT + gctUINT32 bankAlignment; + gceSTATUS status; +#endif + + if (Memory->sentinel[Bank].VidMem.nextFree == gcvNULL) + { + /* No free nodes left. */ + return gcvNULL; + } + +#if gcdENABLE_BANK_ALIGNMENT + /* Walk all free nodes until we have one that is big enough or we have + ** reached the sentinel. */ + for (node = Memory->sentinel[Bank].VidMem.nextFree; + node->VidMem.bytes != 0; + node = node->VidMem.nextFree) + { + gcmkONERROR(_GetSurfaceBankAlignment( + Type, + node->VidMem.memory->baseAddress + node->VidMem.offset, + &bankAlignment)); + + bankAlignment = gcmALIGN(bankAlignment, *Alignment); + + /* Compute number of bytes to skip for alignment. */ + alignment = (*Alignment == 0) + ? 0 + : (*Alignment - (node->VidMem.offset % *Alignment)); + + if (alignment == *Alignment) + { + /* Node is already aligned. */ + alignment = 0; + } + + if (node->VidMem.bytes >= Bytes + alignment + bankAlignment) + { + /* This node is big enough. */ + *Alignment = alignment + bankAlignment; + return node; + } + } +#endif + + /* Walk all free nodes until we have one that is big enough or we have + reached the sentinel. */ + for (node = Memory->sentinel[Bank].VidMem.nextFree; + node->VidMem.bytes != 0; + node = node->VidMem.nextFree) + { + + gctINT modulo = gckMATH_ModuloInt(node->VidMem.offset, *Alignment); + + /* Compute number of bytes to skip for alignment. */ + alignment = (*Alignment == 0) ? 0 : (*Alignment - modulo); + + if (alignment == *Alignment) + { + /* Node is already aligned. */ + alignment = 0; + } + + if (node->VidMem.bytes >= Bytes + alignment) + { + /* This node is big enough. */ + *Alignment = alignment; + return node; + } + } + +#if gcdENABLE_BANK_ALIGNMENT +OnError: +#endif + /* Not enough memory. */ + return gcvNULL; +} + +/******************************************************************************* +** +** gckVIDMEM_AllocateLinear +** +** Allocate linear memory from the gckVIDMEM object. +** +** INPUT: +** +** gckVIDMEM Memory +** Pointer to an gckVIDMEM object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** gctUINT32 Alignment +** Byte alignment for allocation. +** +** gceSURF_TYPE Type +** Type of surface to allocate (use by bank optimization). +** +** OUTPUT: +** +** gcuVIDMEM_NODE_PTR * Node +** Pointer to a variable that will hold the allocated memory node. +*/ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ) +{ + gceSTATUS status; + gcuVIDMEM_NODE_PTR node; + gctUINT32 alignment; + gctINT bank, i; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Memory=0x%x Bytes=%lu Alignment=%u Type=%d", + Memory, Bytes, Alignment, Type); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + gcmkVERIFY_ARGUMENT(Type < gcvSURF_NUM_TYPES); + + /* Acquire the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + + acquired = gcvTRUE; +#if !gcdUSE_VIDMEM_PER_PID + + if (Bytes > Memory->freeBytes) + { + /* Not enough memory. */ + status = gcvSTATUS_OUT_OF_MEMORY; + goto OnError; + } +#endif + +#if gcdSMALL_BLOCK_SIZE + if ((Memory->freeBytes < (Memory->bytes/gcdRATIO_FOR_SMALL_MEMORY)) + && (Bytes >= gcdSMALL_BLOCK_SIZE) + ) + { + /* The left memory is for small memory.*/ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } +#endif + + /* Find the default bank for this surface type. */ + gcmkASSERT((gctINT) Type < gcmCOUNTOF(Memory->mapping)); + bank = Memory->mapping[Type]; + alignment = Alignment; + +#if gcdUSE_VIDMEM_PER_PID + if (Bytes <= Memory->freeBytes) + { +#endif + /* Find a free node in the default bank. */ + node = _FindNode(Memory, bank, Bytes, Type, &alignment); + + /* Out of memory? */ + if (node == gcvNULL) + { + /* Walk all lower banks. */ + for (i = bank - 1; i >= 0; --i) + { + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, Type, &alignment); + if (node != gcvNULL) + { + break; + } + } + } + + if (node == gcvNULL) + { + /* Walk all upper banks. */ + for (i = bank + 1; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + if (Memory->sentinel[i].VidMem.nextFree == gcvNULL) + { + /* Abort when we reach unused banks. */ + break; + } + + /* Find a free node inside the current bank. */ + node = _FindNode(Memory, i, Bytes, Type, &alignment); + if (node != gcvNULL) + { + break; + } + } + } +#if gcdUSE_VIDMEM_PER_PID + } +#endif + + if (node == gcvNULL) + { + /* Out of memory. */ +#if gcdUSE_VIDMEM_PER_PID + /* Allocate more memory from shared pool. */ + gctSIZE_T bytes; + gctPHYS_ADDR physical_temp; + gctUINT32 physical; + gctPOINTER logical; + + bytes = gcmALIGN(Bytes, gcdUSE_VIDMEM_PER_PID_SIZE); + + gcmkONERROR(gckOS_AllocateContiguous(Memory->os, + gcvTRUE, + &bytes, + &physical_temp, + &logical)); + + /* physical address is returned as 0 for user space. workaround. */ + if (physical_temp == gcvNULL) + { + gcmkONERROR(gckOS_GetPhysicalAddress(Memory->os, logical, &physical)); + } + + /* Allocate one gcuVIDMEM_NODE union. */ + gcmkONERROR( + gckOS_Allocate(Memory->os, + gcmSIZEOF(gcuVIDMEM_NODE), + (gctPOINTER *) &node)); + + /* Initialize gcuVIDMEM_NODE union. */ + node->VidMem.memory = Memory; + + node->VidMem.offset = 0; + node->VidMem.bytes = bytes; + node->VidMem.alignment = 0; + node->VidMem.physical = physical; + node->VidMem.pool = gcvPOOL_UNKNOWN; + + node->VidMem.locked = 0; + +#ifdef __QNXNTO__ + gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID)); + node->VidMem.logical = logical; + gcmkASSERT(logical != gcvNULL); +#endif + + /* Insert node behind sentinel node. */ + node->VidMem.next = Memory->sentinel[bank].VidMem.next; + node->VidMem.prev = &Memory->sentinel[bank]; + Memory->sentinel[bank].VidMem.next = node->VidMem.next->VidMem.prev = node; + + /* Insert free node behind sentinel node. */ + node->VidMem.nextFree = Memory->sentinel[bank].VidMem.nextFree; + node->VidMem.prevFree = &Memory->sentinel[bank]; + Memory->sentinel[bank].VidMem.nextFree = node->VidMem.nextFree->VidMem.prevFree = node; + + Memory->freeBytes += bytes; +#else + status = gcvSTATUS_OUT_OF_MEMORY; + goto OnError; +#endif + } + + /* Do we have an alignment? */ + if (alignment > 0) + { + /* Split the node so it is aligned. */ + if (_Split(Memory->os, node, alignment)) + { + /* Successful split, move to aligned node. */ + node = node->VidMem.next; + + /* Remove alignment. */ + alignment = 0; + } + } + + /* Do we have enough memory after the allocation to split it? */ + if (node->VidMem.bytes - Bytes > Memory->threshold) + { + /* Adjust the node size. */ + _Split(Memory->os, node, Bytes); + } + + /* Remove the node from the free list. */ + node->VidMem.prevFree->VidMem.nextFree = node->VidMem.nextFree; + node->VidMem.nextFree->VidMem.prevFree = node->VidMem.prevFree; + node->VidMem.nextFree = + node->VidMem.prevFree = gcvNULL; + + /* Fill in the information. */ + node->VidMem.alignment = alignment; + node->VidMem.memory = Memory; +#ifdef __QNXNTO__ +#if !gcdUSE_VIDMEM_PER_PID + node->VidMem.logical = gcvNULL; + gcmkONERROR(gckOS_GetProcessID(&node->VidMem.processID)); +#else + gcmkASSERT(node->VidMem.logical != gcvNULL); +#endif +#endif + + /* Adjust the number of free bytes. */ + Memory->freeBytes -= node->VidMem.bytes; + + node->VidMem.freePending = gcvFALSE; + +#if gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG + node->VidMem.kernelVirtual = gcvNULL; +#endif + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + + /* Return the pointer to the node. */ + *Node = node; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Allocated %u bytes @ 0x%x [0x%08X]", + node->VidMem.bytes, node, node->VidMem.offset); + + /* Success. */ + gcmkFOOTER_ARG("*Node=0x%x", *Node); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Free +** +** Free an allocated video memory node. +** +** INPUT: +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ) +{ + gceSTATUS status; + gckKERNEL kernel = gcvNULL; + gckVIDMEM memory = gcvNULL; + gcuVIDMEM_NODE_PTR node; + gctBOOL mutexAcquired = gcvFALSE; + gckOS os = gcvFALSE; + gctBOOL acquired = gcvFALSE; + gctINT32 i, totalLocked; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked > 0) + { + /* Client still has a lock, defer free op 'till when lock reaches 0. */ + Node->VidMem.freePending = gcvTRUE; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Node 0x%x is locked (%d)... deferring free.", + Node, Node->VidMem.locked); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Extract pointer to gckVIDMEM object owning the node. */ + memory = Node->VidMem.memory; + + /* Acquire the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(memory->os, memory->mutex, gcvINFINITE)); + + mutexAcquired = gcvTRUE; + +#ifdef __QNXNTO__ +#if !gcdUSE_VIDMEM_PER_PID + /* Reset. */ + Node->VidMem.processID = 0; + Node->VidMem.logical = gcvNULL; +#endif + + /* Don't try to re-free an already freed node. */ + if ((Node->VidMem.nextFree == gcvNULL) + && (Node->VidMem.prevFree == gcvNULL) + ) +#endif + { +#if gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG + if (Node->VidMem.kernelVirtual) + { + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "%s(%d) Unmap %x from kernel space.", + __FUNCTION__, __LINE__, + Node->VidMem.kernelVirtual); + + gcmkVERIFY_OK( + gckOS_UnmapPhysical(memory->os, + Node->VidMem.kernelVirtual, + Node->VidMem.bytes)); + + Node->VidMem.kernelVirtual = gcvNULL; + } +#endif + /* Update the number of free bytes. */ + memory->freeBytes += Node->VidMem.bytes; + + /* Find the next free node. */ + for (node = Node->VidMem.next; + node != gcvNULL && node->VidMem.nextFree == gcvNULL; + node = node->VidMem.next) ; + + /* Insert this node in the free list. */ + Node->VidMem.nextFree = node; + Node->VidMem.prevFree = node->VidMem.prevFree; + + Node->VidMem.prevFree->VidMem.nextFree = + node->VidMem.prevFree = Node; + + /* Is the next node a free node and not the sentinel? */ + if ((Node->VidMem.next == Node->VidMem.nextFree) + && (Node->VidMem.next->VidMem.bytes != 0) + ) + { + /* Merge this node with the next node. */ + gcmkONERROR(_Merge(memory->os, node = Node)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + + /* Is the previous node a free node and not the sentinel? */ + if ((Node->VidMem.prev == Node->VidMem.prevFree) + && (Node->VidMem.prev->VidMem.bytes != 0) + ) + { + /* Merge this node with the previous node. */ + gcmkONERROR(_Merge(memory->os, node = Node->VidMem.prev)); + gcmkASSERT(node->VidMem.nextFree != node); + gcmkASSERT(node->VidMem.prevFree != node); + } + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(memory->os, memory->mutex)); + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Node 0x%x is freed.", + Node); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /*************************** Virtual Memory *******************************/ + + /* Get gckKERNEL object. */ + kernel = Node->Virtual.kernel; + + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(kernel, gcvOBJ_KERNEL); + + /* Get the gckOS object pointer. */ + os = kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + for (i = 0, totalLocked = 0; i < gcdCORE_COUNT; i++) + { + totalLocked += Node->Virtual.lockeds[i]; + } + + if (totalLocked > 0) + { + gcmkTRACE_ZONE(gcvLEVEL_ERROR, gcvZONE_VIDMEM, + "gckVIDMEM_Free: Virtual node 0x%x is locked (%d)", + Node, totalLocked); + + /* Set Flag */ + Node->Virtual.freed = gcvTRUE; + + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + else + { + /* Free the virtual memory. */ + gcmkVERIFY_OK(gckOS_FreePagedMemory(kernel->os, + Node->Virtual.physical, + Node->Virtual.bytes)); + + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + + /* Destroy the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (mutexAcquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex( + memory->os, memory->mutex + )); + } + + if (acquired) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + + +#ifdef __QNXNTO__ +/******************************************************************************* +** +** gcoVIDMEM_FreeHandleMemory +** +** Free all allocated video memory nodes for a handle. +** +** INPUT: +** +** gcoVIDMEM Memory +** Pointer to an gcoVIDMEM object.. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckVIDMEM_FreeHandleMemory( + IN gckKERNEL Kernel, + IN gckVIDMEM Memory, + IN gctUINT32 Pid + ) +{ + gceSTATUS status; + gctBOOL mutex = gcvFALSE; + gcuVIDMEM_NODE_PTR node; + gctINT i; + gctUINT32 nodeCount = 0, byteCount = 0; + gctBOOL again; + + gcmkHEADER_ARG("Kernel=0x%x, Memory=0x%x Pid=0x%u", Kernel, Memory, Pid); + + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_OBJECT(Memory, gcvOBJ_VIDMEM); + + gcmkONERROR(gckOS_AcquireMutex(Memory->os, Memory->mutex, gcvINFINITE)); + mutex = gcvTRUE; + + /* Walk all sentinels. */ + for (i = 0; i < gcmCOUNTOF(Memory->sentinel); ++i) + { + /* Bail out of the heap if it is not used. */ + if (Memory->sentinel[i].VidMem.next == gcvNULL) + { + break; + } + + do + { + again = gcvFALSE; + + /* Walk all the nodes until we reach the sentinel. */ + for (node = Memory->sentinel[i].VidMem.next; + node->VidMem.bytes != 0; + node = node->VidMem.next) + { + /* Free the node if it was allocated by Handle. */ + if (node->VidMem.processID == Pid) + { + /* Unlock video memory. */ + while (node->VidMem.locked > 0) + { + gckVIDMEM_Unlock(Kernel, node, gcvSURF_TYPE_UNKNOWN, gcvNULL); + } + + nodeCount++; + byteCount += node->VidMem.bytes; + + /* Free video memory. */ + gcmkVERIFY_OK(gckVIDMEM_Free(node)); + + /* + * Freeing may cause a merge which will invalidate our iteration. + * Don't be clever, just restart. + */ + again = gcvTRUE; + + break; + } +#if gcdUSE_VIDMEM_PER_PID + else + { + gcmkASSERT(node->VidMem.processID == Pid); + } +#endif + } + } + while (again); + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (mutex) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Memory->os, Memory->mutex)); + } + + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** _NeedVirtualMapping +** +** Whether setup GPU page table for video node. +** +** INPUT: +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** gceCORE Core +** Id of current GPU. +** +** OUTPUT: +** gctBOOL * NeedMapping +** A pointer hold the result whether Node should be mapping. +*/ +static gceSTATUS +_NeedVirtualMapping( + IN gckKERNEL Kernel, + IN gceCORE Core, + IN gcuVIDMEM_NODE_PTR Node, + OUT gctBOOL * NeedMapping +) +{ + gceSTATUS status; + gctUINT32 phys; + gctUINT32 end; + gcePOOL pool; + gctUINT32 offset; + + gcmkHEADER_ARG("Node=0x%X", Node); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Kernel != gcvNULL); + gcmkVERIFY_ARGUMENT(Node != gcvNULL); + gcmkVERIFY_ARGUMENT(NeedMapping != gcvNULL); + gcmkVERIFY_ARGUMENT(Core < gcdCORE_COUNT); + + if (Node->Virtual.contiguous) + { +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + *NeedMapping = gcvFALSE; + } + else +#endif + { + /* For cores which can't access all physical address. */ + gcmkONERROR(gckOS_GetPhysicalAddress(Kernel->os, + Node->Virtual.logical, + &phys)); + + /* If part of region is belong to gcvPOOL_VIRTUAL, + ** whole region has to be mapped. */ + end = phys + Node->Virtual.bytes - 1; + + gcmkONERROR(gckHARDWARE_SplitMemory( + Kernel->hardware, end, &pool, &offset + )); + + *NeedMapping = (pool == gcvPOOL_VIRTUAL); + } + } + else + { + *NeedMapping = gcvTRUE; + } + + gcmkFOOTER_ARG("*NeedMapping=%d", *NeedMapping); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Lock +** +** Lock a video memory node and return its hardware specific address. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a gcuVIDMEM_NODE union. +** +** OUTPUT: +** +** gctUINT32 * Address +** Pointer to a variable that will hold the hardware specific address. +*/ +gceSTATUS +gckVIDMEM_Lock( + IN gckKERNEL Kernel, + IN gcuVIDMEM_NODE_PTR Node, + IN gctBOOL Cacheable, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gctBOOL locked = gcvFALSE; + gckOS os = gcvNULL; + gctBOOL needMapping; + + gcmkHEADER_ARG("Node=0x%x", Node); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Cacheable == gcvTRUE) + { + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + + /* Increment the lock count. */ + Node->VidMem.locked ++; + + /* Return the address of the node. */ +#if !gcdUSE_VIDMEM_PER_PID + *Address = Node->VidMem.memory->baseAddress + + Node->VidMem.offset + + Node->VidMem.alignment; +#else + *Address = Node->VidMem.physical; +#endif + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Locked node 0x%x (%d) @ 0x%08X", + Node, + Node->VidMem.locked, + *Address); + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckKERNEL object pointer. */ + gcmkVERIFY_OBJECT(Node->Virtual.kernel, gcvOBJ_KERNEL); + + /* Extract the gckOS object pointer. */ + os = Node->Virtual.kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR(gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + acquired = gcvTRUE; + + gcmkONERROR( + gckOS_LockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Cacheable, + &Node->Virtual.logical, + &Node->Virtual.pageCount)); + + /* Increment the lock count. */ + if (Node->Virtual.lockeds[Kernel->core] ++ == 0) + { + /* Is this node pending for a final unlock? */ +#ifdef __QNXNTO__ + if (!Node->Virtual.contiguous && Node->Virtual.unlockPendings[Kernel->core]) + { + /* Make sure we have a page table. */ + gcmkASSERT(Node->Virtual.pageTables[Kernel->core] != gcvNULL); + + /* Remove pending unlock. */ + Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE; + } + + /* First lock - create a page table. */ + gcmkASSERT(Node->Virtual.pageTables[Kernel->core] == gcvNULL); + + /* Make sure we mark our node as not flushed. */ + Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE; +#endif + + locked = gcvTRUE; + + gcmkONERROR(_NeedVirtualMapping(Kernel, Kernel->core, Node, &needMapping)); + + if (needMapping == gcvFALSE) + { + /* Get physical address directly */ + gcmkONERROR(gckOS_GetPhysicalAddress(os, + Node->Virtual.logical, + &Node->Virtual.addresses[Kernel->core])); + } + else + { +#if gcdENABLE_VG + if (Kernel->vg != gcvNULL) + { + /* Allocate pages inside the MMU. */ + gcmkONERROR( + gckVGMMU_AllocatePages(Kernel->vg->mmu, + Node->Virtual.pageCount, + &Node->Virtual.pageTables[Kernel->core], + &Node->Virtual.addresses[Kernel->core])); + } + else +#endif + { + /* Allocate pages inside the MMU. */ + gcmkONERROR( + gckMMU_AllocatePages(Kernel->mmu, + Node->Virtual.pageCount, + &Node->Virtual.pageTables[Kernel->core], + &Node->Virtual.addresses[Kernel->core])); + } + + Node->Virtual.lockKernels[Kernel->core] = Kernel; + + /* Map the pages. */ +#ifdef __QNXNTO__ + gcmkONERROR( + gckOS_MapPagesEx(os, + Kernel->core, + Node->Virtual.physical, + Node->Virtual.logical, + Node->Virtual.pageCount, + Node->Virtual.pageTables[Kernel->core])); +#else + gcmkONERROR( + gckOS_MapPagesEx(os, + Kernel->core, + Node->Virtual.physical, + Node->Virtual.pageCount, + Node->Virtual.pageTables[Kernel->core])); +#endif + +#if gcdENABLE_VG + if (Kernel->core != gcvCORE_VG) +#endif + { + gcmkONERROR(gckMMU_Flush(Kernel->mmu)); + } + } + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Mapped virtual node 0x%x to 0x%08X", + Node, + Node->Virtual.addresses[Kernel->core]); + } + + /* Return hardware address. */ + *Address = Node->Virtual.addresses[Kernel->core]; + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Success. */ + gcmkFOOTER_ARG("*Address=%08x", *Address); + return gcvSTATUS_OK; + +OnError: + if (locked) + { + if (Node->Virtual.pageTables[Kernel->core] != gcvNULL) + { +#if gcdENABLE_VG + if (Kernel->vg != gcvNULL) + { + /* Free the pages from the MMU. */ + gcmkVERIFY_OK( + gckVGMMU_FreePages(Kernel->vg->mmu, + Node->Virtual.pageTables[Kernel->core], + Node->Virtual.pageCount)); + } + else +#endif + { + /* Free the pages from the MMU. */ + gcmkVERIFY_OK( + gckMMU_FreePages(Kernel->mmu, + Node->Virtual.pageTables[Kernel->core], + Node->Virtual.pageCount)); + } + Node->Virtual.pageTables[Kernel->core] = gcvNULL; + Node->Virtual.lockKernels[Kernel->core] = gcvNULL; + } + + /* Unlock the pages. */ + gcmkVERIFY_OK( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical + )); + + Node->Virtual.lockeds[Kernel->core]--; + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckVIDMEM_Unlock +** +** Unlock a video memory node. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcuVIDMEM_NODE_PTR Node +** Pointer to a locked gcuVIDMEM_NODE union. +** +** gceSURF_TYPE Type +** Type of surface to unlock. +** +** gctBOOL * Asynchroneous +** Pointer to a variable specifying whether the surface should be +** unlocked asynchroneously or not. +** +** OUTPUT: +** +** gctBOOL * Asynchroneous +** Pointer to a variable receiving the number of bytes used in the +** command buffer specified by 'Commands'. If gcvNULL, there is no +** command buffer. +*/ +gceSTATUS +gckVIDMEM_Unlock( + IN gckKERNEL Kernel, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ) +{ + gceSTATUS status; + gckHARDWARE hardware; + gctPOINTER buffer; + gctSIZE_T requested, bufferSize; + gckCOMMAND command = gcvNULL; + gceKERNEL_FLUSH flush; + gckOS os = gcvNULL; + gctBOOL acquired = gcvFALSE; + gctBOOL commitEntered = gcvFALSE; + gctINT32 i, totalLocked; + + gcmkHEADER_ARG("Node=0x%x Type=%d *Asynchroneous=%d", + Node, Type, gcmOPT_VALUE(Asynchroneous)); + + /* Verify the arguments. */ + if ((Node == gcvNULL) + || (Node->VidMem.memory == gcvNULL) + ) + { + /* Invalid object. */ + gcmkONERROR(gcvSTATUS_INVALID_OBJECT); + } + + /**************************** Video Memory ********************************/ + + if (Node->VidMem.memory->object.type == gcvOBJ_VIDMEM) + { + if (Node->VidMem.locked <= 0) + { + /* The surface was not locked. */ + status = gcvSTATUS_MEMORY_UNLOCKED; + goto OnError; + } + + /* Decrement the lock count. */ + Node->VidMem.locked --; + + if (Asynchroneous != gcvNULL) + { + /* No need for any events. */ + *Asynchroneous = gcvFALSE; + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Unlocked node 0x%x (%d)", + Node, + Node->VidMem.locked); + +#ifdef __QNXNTO__ + /* Unmap the video memory */ + if ((Node->VidMem.locked == 0) && (Node->VidMem.logical != gcvNULL)) + { + if (Kernel->core == gcvCORE_VG) + { + gckKERNEL_UnmapVideoMemory(Kernel, + Node->VidMem.logical, + Node->VidMem.processID, + Node->VidMem.bytes); + Node->VidMem.logical = gcvNULL; + } + } +#endif /* __QNXNTO__ */ + + if (Node->VidMem.freePending && (Node->VidMem.locked == 0)) + { + /* Client has unlocked node previously attempted to be freed by compositor. Free now. */ + Node->VidMem.freePending = gcvFALSE; + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Deferred-freeing Node 0x%x.", + Node); + gcmkONERROR(gckVIDMEM_Free(Node)); + } + } + + /*************************** Virtual Memory *******************************/ + + else + { + /* Verify the gckHARDWARE object pointer. */ + hardware = Kernel->hardware; + gcmkVERIFY_OBJECT(hardware, gcvOBJ_HARDWARE); + + /* Verify the gckCOMMAND object pointer. */ + command = Kernel->command; + gcmkVERIFY_OBJECT(command, gcvOBJ_COMMAND); + + /* Get the gckOS object pointer. */ + os = Kernel->os; + gcmkVERIFY_OBJECT(os, gcvOBJ_OS); + + /* Grab the mutex. */ + gcmkONERROR( + gckOS_AcquireMutex(os, Node->Virtual.mutex, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Asynchroneous == gcvNULL) + { + if (Node->Virtual.lockeds[Kernel->core] == 0) + { + status = gcvSTATUS_MEMORY_UNLOCKED; + goto OnError; + } + + /* Decrement lock count. */ + -- Node->Virtual.lockeds[Kernel->core]; + + /* See if we can unlock the resources. */ + if (Node->Virtual.lockeds[Kernel->core] == 0) + { + /* Free the page table. */ + if (Node->Virtual.pageTables[Kernel->core] != gcvNULL) + { +#if gcdENABLE_VG + if (Kernel->vg != gcvNULL) + { + gcmkONERROR( + gckVGMMU_FreePages(Kernel->vg->mmu, + Node->Virtual.pageTables[Kernel->core], + Node->Virtual.pageCount)); + } + else +#endif + { + gcmkONERROR( + gckMMU_FreePages(Kernel->mmu, + Node->Virtual.pageTables[Kernel->core], + Node->Virtual.pageCount)); + } + /* Mark page table as freed. */ + Node->Virtual.pageTables[Kernel->core] = gcvNULL; + Node->Virtual.lockKernels[Kernel->core] = gcvNULL; + } + +#ifdef __QNXNTO__ + /* Mark node as unlocked. */ + Node->Virtual.unlockPendings[Kernel->core] = gcvFALSE; +#endif + } + + for (i = 0, totalLocked = 0; i < gcdCORE_COUNT; i++) + { + totalLocked += Node->Virtual.lockeds[i]; + } + + if (totalLocked == 0) + { + /* Owner have already freed this node + ** and we are the last one to unlock, do + ** real free */ + if (Node->Virtual.freed) + { + /* Free the virtual memory. */ + gcmkVERIFY_OK(gckOS_FreePagedMemory(Kernel->os, + Node->Virtual.physical, + Node->Virtual.bytes)); + + /* Release mutex before node is destroyed */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + + acquired = gcvFALSE; + + /* Destroy the gcuVIDMEM_NODE union. */ + gcmkVERIFY_OK(gckVIDMEM_DestroyVirtual(Node)); + + /* Node has been destroyed, so we should not touch it any more */ + gcmkFOOTER(); + return gcvSTATUS_OK; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Unmapped virtual node 0x%x from 0x%08X", + Node, Node->Virtual.addresses[Kernel->core]); + + } + + else + { + /* If we need to unlock a node from virtual memory we have to be + ** very carefull. If the node is still inside the caches we + ** might get a bus error later if the cache line needs to be + ** replaced. So - we have to flush the caches before we do + ** anything. */ + + /* gckCommand_EnterCommit() can't be called in interrupt handler because + ** of a dead lock situation: + ** process call Command_Commit(), and acquire Command->mutexQueue in + ** gckCOMMAND_EnterCommit(). Then it will wait for a signal which depends + ** on interrupt handler to generate, if interrupt handler enter + ** gckCommand_EnterCommit(), process will never get the signal. */ + + /* So, flush cache when we still in process context, and then ask caller to + ** schedule a event. */ + + gcmkONERROR( + gckOS_UnlockPages(os, + Node->Virtual.physical, + Node->Virtual.bytes, + Node->Virtual.logical)); + + if (!Node->Virtual.contiguous + && (Node->Virtual.lockeds[Kernel->core] == 1) + ) + { + if (Type == gcvSURF_BITMAP) + { + /* Flush 2D cache. */ + flush = gcvFLUSH_2D; + } + else if (Type == gcvSURF_RENDER_TARGET) + { + /* Flush color cache. */ + flush = gcvFLUSH_COLOR; + } + else if (Type == gcvSURF_DEPTH) + { + /* Flush depth cache. */ + flush = gcvFLUSH_DEPTH; + } + else + { + /* No flush required. */ + flush = (gceKERNEL_FLUSH) 0; + } + + gcmkONERROR( + gckHARDWARE_Flush(hardware, flush, gcvNULL, &requested)); + + if (requested != 0) + { + /* Acquire the command queue. */ + gcmkONERROR(gckCOMMAND_EnterCommit(command, gcvFALSE)); + commitEntered = gcvTRUE; + + gcmkONERROR(gckCOMMAND_Reserve( + command, requested, &buffer, &bufferSize + )); + + gcmkONERROR(gckHARDWARE_Flush( + hardware, flush, buffer, &bufferSize + )); + + /* Mark node as pending. */ +#ifdef __QNXNTO__ + Node->Virtual.unlockPendings[Kernel->core] = gcvTRUE; +#endif + + gcmkONERROR(gckCOMMAND_Execute(command, requested)); + + /* Release the command queue. */ + gcmkONERROR(gckCOMMAND_ExitCommit(command, gcvFALSE)); + commitEntered = gcvFALSE; + } + } + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_VIDMEM, + "Scheduled unlock for virtual node 0x%x", + Node); + + /* Schedule the surface to be unlocked. */ + *Asynchroneous = gcvTRUE; + } + + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + + acquired = gcvFALSE; + } + + /* Success. */ + gcmkFOOTER_ARG("*Asynchroneous=%d", gcmOPT_VALUE(Asynchroneous)); + return gcvSTATUS_OK; + +OnError: + if (commitEntered) + { + /* Release the command queue mutex. */ + gcmkVERIFY_OK(gckCOMMAND_ExitCommit(command, gcvFALSE)); + } + + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(os, Node->Virtual.mutex)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal.h new file mode 100644 index 0000000..c87bb1e --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal.h @@ -0,0 +1,2372 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_h_ +#define __gc_hal_h_ + +#include "gc_hal_rename.h" +#include "gc_hal_types.h" +#include "gc_hal_enum.h" +#include "gc_hal_base.h" +#include "gc_hal_profiler.h" +#include "gc_hal_driver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* Alignment Macros ******************************* +\******************************************************************************/ + +#define gcmALIGN(n, align) \ +( \ + ((n) + ((align) - 1)) & ~((align) - 1) \ +) + +#define gcmALIGN_BASE(n, align) \ +( \ + (n) & ~((align) - 1) \ +) + +/******************************************************************************\ +***************************** Element Count Macro ***************************** +\******************************************************************************/ + +#define gcmSIZEOF(a) \ +( \ + (gctSIZE_T) (sizeof(a)) \ +) + +#define gcmCOUNTOF(a) \ +( \ + sizeof(a) / sizeof(a[0]) \ +) + +/******************************************************************************\ +******************************** gcsOBJECT Object ******************************* +\******************************************************************************/ + +/* Type of objects. */ +typedef enum _gceOBJECT_TYPE +{ + gcvOBJ_UNKNOWN = 0, + gcvOBJ_2D = gcmCC('2','D',' ',' '), + gcvOBJ_3D = gcmCC('3','D',' ',' '), + gcvOBJ_ATTRIBUTE = gcmCC('A','T','T','R'), + gcvOBJ_BRUSHCACHE = gcmCC('B','R','U','$'), + gcvOBJ_BRUSHNODE = gcmCC('B','R','U','n'), + gcvOBJ_BRUSH = gcmCC('B','R','U','o'), + gcvOBJ_BUFFER = gcmCC('B','U','F','R'), + gcvOBJ_COMMAND = gcmCC('C','M','D',' '), + gcvOBJ_COMMANDBUFFER = gcmCC('C','M','D','B'), + gcvOBJ_CONTEXT = gcmCC('C','T','X','T'), + gcvOBJ_DEVICE = gcmCC('D','E','V',' '), + gcvOBJ_DUMP = gcmCC('D','U','M','P'), + gcvOBJ_EVENT = gcmCC('E','V','N','T'), + gcvOBJ_FUNCTION = gcmCC('F','U','N','C'), + gcvOBJ_HAL = gcmCC('H','A','L',' '), + gcvOBJ_HARDWARE = gcmCC('H','A','R','D'), + gcvOBJ_HEAP = gcmCC('H','E','A','P'), + gcvOBJ_INDEX = gcmCC('I','N','D','X'), + gcvOBJ_INTERRUPT = gcmCC('I','N','T','R'), + gcvOBJ_KERNEL = gcmCC('K','E','R','N'), + gcvOBJ_KERNEL_FUNCTION = gcmCC('K','F','C','N'), + gcvOBJ_MEMORYBUFFER = gcmCC('M','E','M','B'), + gcvOBJ_MMU = gcmCC('M','M','U',' '), + gcvOBJ_OS = gcmCC('O','S',' ',' '), + gcvOBJ_OUTPUT = gcmCC('O','U','T','P'), + gcvOBJ_PAINT = gcmCC('P','N','T',' '), + gcvOBJ_PATH = gcmCC('P','A','T','H'), + gcvOBJ_QUEUE = gcmCC('Q','U','E',' '), + gcvOBJ_SAMPLER = gcmCC('S','A','M','P'), + gcvOBJ_SHADER = gcmCC('S','H','D','R'), + gcvOBJ_STREAM = gcmCC('S','T','R','M'), + gcvOBJ_SURF = gcmCC('S','U','R','F'), + gcvOBJ_TEXTURE = gcmCC('T','X','T','R'), + gcvOBJ_UNIFORM = gcmCC('U','N','I','F'), + gcvOBJ_VARIABLE = gcmCC('V','A','R','I'), + gcvOBJ_VERTEX = gcmCC('V','R','T','X'), + gcvOBJ_VIDMEM = gcmCC('V','M','E','M'), + gcvOBJ_VG = gcmCC('V','G',' ',' '), +} +gceOBJECT_TYPE; + +/* gcsOBJECT object defintinon. */ +typedef struct _gcsOBJECT +{ + /* Type of an object. */ + gceOBJECT_TYPE type; +} +gcsOBJECT; + +typedef struct _gckHARDWARE * gckHARDWARE; + +/* CORE flags. */ +typedef enum _gceCORE +{ + gcvCORE_MAJOR = 0x0, + gcvCORE_2D = 0x1, + gcvCORE_VG = 0x2 +} +gceCORE; + +#define gcdCORE_COUNT 3 + +/******************************************************************************* +** +** gcmVERIFY_OBJECT +** +** Assert if an object is invalid or is not of the specified type. If the +** object is invalid or not of the specified type, gcvSTATUS_INVALID_OBJECT +** will be returned from the current function. In retail mode this macro +** does nothing. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#if gcmIS_DEBUG(gcdDEBUG_TRACE) +#define _gcmVERIFY_OBJECT(prefix, obj, t) \ + if ((obj) == gcvNULL) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: NULL"); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT((obj) != gcvNULL); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } \ + else if (((gcsOBJECT*) (obj))->type != t) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT failed: %c%c%c%c", \ + gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_OBJECT); \ + return gcvSTATUS_INVALID_OBJECT; \ + } + +# define gcmVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcm, obj, t) +# define gcmkVERIFY_OBJECT(obj, t) _gcmVERIFY_OBJECT(gcmk, obj, t) +#else +# define gcmVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +# define gcmkVERIFY_OBJECT(obj, t) do {} while (gcvFALSE) +#endif + +/******************************************************************************/ +/*VERIFY_OBJECT if special return expected*/ +/******************************************************************************/ +#ifndef EGL_API_ANDROID +# define _gcmVERIFY_OBJECT_RETURN(prefix, obj, t, retVal) \ + do \ + { \ + if ((obj) == gcvNULL) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT_RETURN failed: NULL"); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT((obj) != gcvNULL); \ + prefix##FOOTER_ARG("retVal=%d", retVal); \ + return retVal; \ + } \ + else if (((gcsOBJECT*) (obj))->type != t) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "VERIFY_OBJECT_RETURN failed: %c%c%c%c", \ + gcmCC_PRINT(((gcsOBJECT*) (obj))->type)); \ + prefix##TRACE(gcvLEVEL_ERROR, " expected: %c%c%c%c", \ + gcmCC_PRINT(t)); \ + prefix##ASSERT(((gcsOBJECT*)(obj))->type == t); \ + prefix##FOOTER_ARG("retVal=%d", retVal); \ + return retVal; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_OBJECT_RETURN(obj, t, retVal) \ + _gcmVERIFY_OBJECT_RETURN(gcm, obj, t, retVal) +# define gcmkVERIFY_OBJECT_RETURN(obj, t, retVal) \ + _gcmVERIFY_OBJECT_RETURN(gcmk, obj, t, retVal) +#else +# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE) +# define gcmVERIFY_OBJECT_RETURN(obj, t) do {} while (gcvFALSE) +#endif + +/******************************************************************************\ +********************************** gckOS Object ********************************* +\******************************************************************************/ + +/* Construct a new gckOS object. */ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ); + +/* Destroy an gckOS object. */ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ); + +/* Query the video memory. */ +gceSTATUS +gckOS_QueryVideoMemory( + IN gckOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free allocated memory. */ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Wrapper for allocation memory.. */ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Wrapper for freeing memory. */ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Allocate paged memory. */ +gceSTATUS +gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ); + +/* Lock pages. */ +gceSTATUS +gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctBOOL Cacheable, + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ); + +/* Map pages. */ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctPOINTER Logical, +#endif + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ); + +/* Map pages. */ +gceSTATUS +gckOS_MapPagesEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPHYS_ADDR Physical, +#ifdef __QNXNTO__ + IN gctPOINTER Logical, +#endif + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ); + +/* Unlock pages. */ +gceSTATUS +gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Free paged memory. */ +gceSTATUS +gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ); + +/* Allocate non-paged memory. */ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non-paged memory. */ +gceSTATUS +gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Get the number fo bytes per page. */ +gceSTATUS +gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ); + +/* Get the physical address of a corresponding logical address. */ +gceSTATUS +gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +/* Get the physical address of a corresponding logical address. */ +gceSTATUS +gckOS_GetPhysicalAddressProcess( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT32 ProcessID, + OUT gctUINT32 * Address + ); + +/* Map physical memory. */ +gceSTATUS +gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap previously mapped physical memory. */ +gceSTATUS +gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +/* Read data from a hardware register. */ +gceSTATUS +gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +/* Read data from a hardware register. */ +gceSTATUS +gckOS_ReadRegisterEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +/* Write data to a hardware register. */ +gceSTATUS +gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Write data to a hardware register. */ +gceSTATUS +gckOS_WriteRegisterEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Write data to a 32-bit memory location. */ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ); + +/* Map physical memory into the process space. */ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap physical memory from the specified process space. */ +gceSTATUS +gckOS_UnmapMemoryEx( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical, + IN gctUINT32 PID + ); + +/* Unmap physical memory from the process space. */ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Create a new mutex. */ +gceSTATUS +gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ); + +/* Atomically exchange a pair of 32-bit values. */ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ); + +/* Atomically exchange a pair of pointers. */ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ); + +#if gcdSMP +gceSTATUS +gckOS_AtomSetMask( + IN gctPOINTER Atom, + IN gctUINT32 Mask + ); + +gceSTATUS +gckOS_AtomClearMask( + IN gctPOINTER Atom, + IN gctUINT32 Mask + ); +#endif + +gceSTATUS +gckOS_DumpGPUState( + IN gckOS Os, + IN gceCORE Core + ); + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ); + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ); + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomSet +** +** Set the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** gctINT32 Value +** The value of the atom. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomSet( + IN gckOS Os, + IN gctPOINTER Atom, + IN gctINT32 Value + ); + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ); + +/* Get time in milliseconds. */ +gceSTATUS +gckOS_GetTicks( + OUT gctUINT32_PTR Time + ); + +/* Compare time value. */ +gceSTATUS +gckOS_TicksAfter( + IN gctUINT32 Time1, + IN gctUINT32 Time2, + OUT gctBOOL_PTR IsAfter + ); + +/* Get time in microseconds. */ +gceSTATUS +gckOS_GetTime( + OUT gctUINT64_PTR Time + ); + +/* Memory barrier. */ +gceSTATUS +gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ); + +/* Map user pointer. */ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ); + +/* Unmap user pointer. */ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ); + +/******************************************************************************* +** +** gckOS_QueryNeedCopy +** +** Query whether the memory can be accessed or mapped directly or it has to be +** copied. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 ProcessID +** Process ID of the current process. +** +** OUTPUT: +** +** gctBOOL_PTR NeedCopy +** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or +** gcvFALSE if the memory can be accessed or mapped dircetly. +*/ +gceSTATUS +gckOS_QueryNeedCopy( + IN gckOS Os, + IN gctUINT32 ProcessID, + OUT gctBOOL_PTR NeedCopy + ); + +/******************************************************************************* +** +** gckOS_CopyFromUserData +** +** Copy data from user to kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER KernelPointer +** Pointer to kernel memory. +** +** gctPOINTER Pointer +** Pointer to user memory. +** +** gctSIZE_T Size +** Number of bytes to copy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_CopyFromUserData( + IN gckOS Os, + IN gctPOINTER KernelPointer, + IN gctPOINTER Pointer, + IN gctSIZE_T Size + ); + +/******************************************************************************* +** +** gckOS_CopyToUserData +** +** Copy data from kernel to user memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER KernelPointer +** Pointer to kernel memory. +** +** gctPOINTER Pointer +** Pointer to user memory. +** +** gctSIZE_T Size +** Number of bytes to copy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_CopyToUserData( + IN gckOS Os, + IN gctPOINTER KernelPointer, + IN gctPOINTER Pointer, + IN gctSIZE_T Size + ); + +#ifdef __QNXNTO__ +/* Map user physical address. */ +gceSTATUS +gckOS_MapUserPhysical( + IN gckOS Os, + IN gctPHYS_ADDR Phys, + OUT gctPOINTER * KernelPointer + ); +#endif + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ); + +gceSTATUS +gckOS_SuspendInterruptEx( + IN gckOS Os, + IN gceCORE Core + ); + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ); + +gceSTATUS +gckOS_ResumeInterruptEx( + IN gckOS Os, + IN gceCORE Core + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Perform a memory copy. */ +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Device I/O control to the kernel HAL layer. */ +gceSTATUS +gckOS_DeviceControl( + IN gckOS Os, + IN gctBOOL FromUser, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + OUT gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ); + +gceSTATUS +gckOS_GetCurrentProcessID( + OUT gctUINT32_PTR ProcessID + ); + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ); + +/******************************************************************************\ +********************************** Signal Object ********************************* +\******************************************************************************/ + +/* Create a signal. */ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Map a user signal to the kernel space. */ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ); + +/* Unmap a user signal */ +gceSTATUS +gckOS_UnmapSignal( + IN gckOS Os, + IN gctSIGNAL Signal + ); + +/* Map user memory. */ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Map user memory. */ +gceSTATUS +gckOS_MapUserMemoryEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +/* Unmap user memory. */ +gceSTATUS +gckOS_UnmapUserMemoryEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +#if !USE_NEW_LINUX_SIGNAL +/* Create signal to be used in the user space. */ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ); + +/* Destroy signal used in the user space. */ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ); + +/* Wait for signal used in the user space. */ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ); + +/* Signal a signal used in the user space. */ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ); +#endif /* USE_NEW_LINUX_SIGNAL */ + +/* Set a signal owned by a process. */ +#if defined(__QNXNTO__) +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctINT Recvid, + IN gctINT Coid + ); +#else +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ); +#endif + +/******************************************************************************\ +** Cache Support +*/ + +gceSTATUS +gckOS_CacheClean( + gckOS Os, + gctUINT32 ProcessID, + gctPHYS_ADDR Handle, + gctPOINTER Physical, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +gceSTATUS +gckOS_CacheFlush( + gckOS Os, + gctUINT32 ProcessID, + gctPHYS_ADDR Handle, + gctPOINTER Physical, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +gceSTATUS +gckOS_CacheInvalidate( + gckOS Os, + gctUINT32 ProcessID, + gctPHYS_ADDR Handle, + gctPOINTER Physical, + gctPOINTER Logical, + gctSIZE_T Bytes + ); + +/******************************************************************************\ +** Debug Support +*/ + +void +gckOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gckOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gckOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gckOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +/******************************************************************************* +** Broadcast interface. +*/ + +typedef enum _gceBROADCAST +{ + /* GPU might be idle. */ + gcvBROADCAST_GPU_IDLE, + + /* A commit is going to happen. */ + gcvBROADCAST_GPU_COMMIT, + + /* GPU seems to be stuck. */ + gcvBROADCAST_GPU_STUCK, + + /* First process gets attached. */ + gcvBROADCAST_FIRST_PROCESS, + + /* Last process gets detached. */ + gcvBROADCAST_LAST_PROCESS, + + /* AXI bus error. */ + gcvBROADCAST_AXI_BUS_ERROR, +} +gceBROADCAST; + +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ); + +gceSTATUS +gckOS_BroadcastHurry( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT Urgency + ); + +gceSTATUS +gckOS_BroadcastCalibrateSpeed( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT Idle, + IN gctUINT Time + ); + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object.ß +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ); + +/******************************************************************************* +** Semaphores. +*/ + +/* Create a new semaphore. */ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ); + +#if gcdENABLE_VG +gceSTATUS +gckOS_CreateSemaphoreVG( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ); +#endif + +/* Delete a semahore. */ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Acquire a semahore. */ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Try to acquire a semahore. */ +gceSTATUS +gckOS_TryAcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/* Release a semahore. */ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ); + +/******************************************************************************* +** Timer API. +*/ + +typedef void (*gctTIMERFUNCTION)(gctPOINTER); + +/* Create a timer. */ +gceSTATUS +gckOS_CreateTimer( + IN gckOS Os, + IN gctTIMERFUNCTION Function, + IN gctPOINTER Data, + OUT gctPOINTER * Timer + ); + +/* Destory a timer. */ +gceSTATUS +gckOS_DestoryTimer( + IN gckOS Os, + IN gctPOINTER Timer + ); + +/* Start a timer. */ +gceSTATUS +gckOS_StartTimer( + IN gckOS Os, + IN gctPOINTER Timer, + IN gctUINT32 Delay + ); + +/* Stop a timer. */ +gceSTATUS +gckOS_StopTimer( + IN gckOS Os, + IN gctPOINTER Timer + ); + +/******************************************************************************\ +********************************* gckHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gckHEAP * gckHEAP; + +/* Construct a new gckHEAP object. */ +gceSTATUS +gckHEAP_Construct( + IN gckOS Os, + IN gctSIZE_T AllocationSize, + OUT gckHEAP * Heap + ); + +/* Destroy an gckHEAP object. */ +gceSTATUS +gckHEAP_Destroy( + IN gckHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gckHEAP_Allocate( + IN gckHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +/* Free memory. */ +gceSTATUS +gckHEAP_Free( + IN gckHEAP Heap, + IN gctPOINTER Node + ); + +/* Profile the heap. */ +gceSTATUS +gckHEAP_ProfileStart( + IN gckHEAP Heap + ); + +gceSTATUS +gckHEAP_ProfileEnd( + IN gckHEAP Heap, + IN gctCONST_STRING Title + ); + + +/******************************************************************************\ +******************************** gckVIDMEM Object ****************************** +\******************************************************************************/ + +typedef struct _gckVIDMEM * gckVIDMEM; +typedef struct _gckKERNEL * gckKERNEL; +typedef struct _gckDB * gckDB; + +/* Construct a new gckVIDMEM object. */ +gceSTATUS +gckVIDMEM_Construct( + IN gckOS Os, + IN gctUINT32 BaseAddress, + IN gctSIZE_T Bytes, + IN gctSIZE_T Threshold, + IN gctSIZE_T Banking, + OUT gckVIDMEM * Memory + ); + +/* Destroy an gckVDIMEM object. */ +gceSTATUS +gckVIDMEM_Destroy( + IN gckVIDMEM Memory + ); + +/* Allocate rectangular memory. */ +gceSTATUS +gckVIDMEM_Allocate( + IN gckVIDMEM Memory, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT BytesPerPixel, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Allocate linear memory. */ +gceSTATUS +gckVIDMEM_AllocateLinear( + IN gckVIDMEM Memory, + IN gctSIZE_T Bytes, + IN gctUINT32 Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Free memory. */ +gceSTATUS +gckVIDMEM_Free( + IN gcuVIDMEM_NODE_PTR Node + ); + +/* Lock memory. */ +gceSTATUS +gckVIDMEM_Lock( + IN gckKERNEL Kernel, + IN gcuVIDMEM_NODE_PTR Node, + IN gctBOOL Cacheable, + OUT gctUINT32 * Address + ); + +/* Unlock memory. */ +gceSTATUS +gckVIDMEM_Unlock( + IN gckKERNEL Kernel, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type, + IN OUT gctBOOL * Asynchroneous + ); + +/* Construct a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_ConstructVirtual( + IN gckKERNEL Kernel, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Destroy a gcuVIDMEM_NODE union for virtual memory. */ +gceSTATUS +gckVIDMEM_DestroyVirtual( + IN gcuVIDMEM_NODE_PTR Node + ); + +/******************************************************************************\ +******************************** gckKERNEL Object ****************************** +\******************************************************************************/ + +struct _gcsHAL_INTERFACE; + +/* Notifications. */ +typedef enum _gceNOTIFY +{ + gcvNOTIFY_INTERRUPT, + gcvNOTIFY_COMMAND_QUEUE, +} +gceNOTIFY; + +/* Flush flags. */ +typedef enum _gceKERNEL_FLUSH +{ + gcvFLUSH_COLOR = 0x01, + gcvFLUSH_DEPTH = 0x02, + gcvFLUSH_TEXTURE = 0x04, + gcvFLUSH_2D = 0x08, + gcvFLUSH_ALL = gcvFLUSH_COLOR + | gcvFLUSH_DEPTH + | gcvFLUSH_TEXTURE + | gcvFLUSH_2D, +} +gceKERNEL_FLUSH; + +/* Construct a new gckKERNEL object. */ +gceSTATUS +gckKERNEL_Construct( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Context, + IN gckDB SharedDB, + OUT gckKERNEL * Kernel + ); + +/* Destroy an gckKERNEL object. */ +gceSTATUS +gckKERNEL_Destroy( + IN gckKERNEL Kernel + ); + +/* Dispatch a user-level command. */ +gceSTATUS +gckKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Query the video memory. */ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Lookup the gckVIDMEM object for a pool. */ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ); + +#if gcdUSE_VIDMEM_PER_PID +gceSTATUS +gckKERNEL_GetVideoMemoryPoolPid( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + IN gctUINT32 Pid, + OUT gckVIDMEM * VideoMemory + ); + +gceSTATUS +gckKERNEL_CreateVideoMemoryPoolPid( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + IN gctUINT32 Pid, + OUT gckVIDMEM * VideoMemory + ); + +gceSTATUS +gckKERNEL_RemoveVideoMemoryPoolPid( + IN gckKERNEL Kernel, + IN gckVIDMEM VideoMemory + ); +#endif + +/* Map video memory. */ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, + IN gctUINT32 Bytes, +#endif + OUT gctPOINTER * Logical + ); + +/* Map video memory. */ +gceSTATUS +gckKERNEL_MapVideoMemoryEx( + IN gckKERNEL Kernel, + IN gceCORE Core, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, +#ifdef __QNXNTO__ + IN gctUINT32 Pid, + IN gctUINT32 Bytes, +#endif + OUT gctPOINTER * Logical + ); + +#ifdef __QNXNTO__ +/* Unmap video memory. */ +gceSTATUS +gckKERNEL_UnmapVideoMemory( + IN gckKERNEL Kernel, + IN gctPOINTER Logical, + IN gctUINT32 Pid, + IN gctUINT32 Bytes + ); +#endif + +/* Map memory. */ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ); + +/* Unmap memory. */ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Notification of events. */ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notifcation, + IN gctBOOL Data + ); + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ); + +/******************************************************************************* +** +** gckKERNEL_Recovery +** +** Try to recover the GPU from a fatal error. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Recovery( + IN gckKERNEL Kernel + ); + +/* Set the value of timeout on HW operation. */ +void +gckKERNEL_SetTimeOut( + IN gckKERNEL Kernel, + IN gctUINT32 timeOut + ); + +/* Get access to the user data. */ +gceSTATUS +gckKERNEL_OpenUserData( + IN gckKERNEL Kernel, + IN gctBOOL NeedCopy, + IN gctPOINTER StaticStorage, + IN gctPOINTER UserPointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ); + +/* Release resources associated with the user data connection. */ +gceSTATUS +gckKERNEL_CloseUserData( + IN gckKERNEL Kernel, + IN gctBOOL NeedCopy, + IN gctBOOL FlushData, + IN gctPOINTER UserPointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ); + +/******************************************************************************\ +******************************* gckHARDWARE Object ***************************** +\******************************************************************************/ + +/* Construct a new gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Construct( + IN gckOS Os, + IN gceCORE Core, + OUT gckHARDWARE * Hardware + ); + +/* Destroy an gckHARDWARE object. */ +gceSTATUS +gckHARDWARE_Destroy( + IN gckHARDWARE Hardware + ); + +/* Get hardware type. */ +gceSTATUS +gckHARDWARE_GetType( + IN gckHARDWARE Hardware, + OUT gceHARDWARE_TYPE * Type + ); + +/* Query system memory requirements. */ +gceSTATUS +gckHARDWARE_QuerySystemMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ); + +/* Build virtual address. */ +gceSTATUS +gckHARDWARE_BuildVirtualAddress( + IN gckHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ); + +/* Query command buffer requirements. */ +gceSTATUS +gckHARDWARE_QueryCommandBuffer( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * Alignment, + OUT gctSIZE_T * ReservedHead, + OUT gctSIZE_T * ReservedTail + ); + +/* Add a WAIT/LINK pair in the command queue. */ +gceSTATUS +gckHARDWARE_WaitLink( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN OUT gctSIZE_T * Bytes, + OUT gctUINT32 * WaitOffset, + OUT gctSIZE_T * WaitBytes + ); + +/* Kickstart the command processor. */ +gceSTATUS +gckHARDWARE_Execute( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, +#ifdef __QNXNTO__ + IN gctPOINTER Physical, + IN gctBOOL PhysicalAddresses, +#endif + IN gctSIZE_T Bytes + ); + +/* Add an END command in the command queue. */ +gceSTATUS +gckHARDWARE_End( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a NOP command in the command queue. */ +gceSTATUS +gckHARDWARE_Nop( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a WAIT command in the command queue. */ +gceSTATUS +gckHARDWARE_Wait( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Count, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a PIPESELECT command in the command queue. */ +gceSTATUS +gckHARDWARE_PipeSelect( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gcePIPE_SELECT Pipe, + IN OUT gctSIZE_T * Bytes + ); + +/* Add a LINK command in the command queue. */ +gceSTATUS +gckHARDWARE_Link( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctPOINTER FetchAddress, + IN gctSIZE_T FetchSize, + IN OUT gctSIZE_T * Bytes + ); + +/* Add an EVENT command in the command queue. */ +gceSTATUS +gckHARDWARE_Event( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT8 Event, + IN gceKERNEL_WHERE FromWhere, + IN OUT gctSIZE_T * Bytes + ); + +/* Query the available memory. */ +gceSTATUS +gckHARDWARE_QueryMemory( + IN gckHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gckHARDWARE_QueryChipIdentity( + IN gckHARDWARE Hardware, + OUT gcsHAL_QUERY_CHIP_IDENTITY_PTR Identity + ); + +/* Query the shader support. */ +gceSTATUS +gckHARDWARE_QueryShaderCaps( + IN gckHARDWARE Hardware, + OUT gctUINT * VertexUniforms, + OUT gctUINT * FragmentUniforms, + OUT gctUINT * Varyings + ); + +/* Split a harwdare specific address into API stuff. */ +gceSTATUS +gckHARDWARE_SplitMemory( + IN gckHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ); + +/* Update command queue tail pointer. */ +gceSTATUS +gckHARDWARE_UpdateQueueTail( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + IN gctUINT32 Offset + ); + +/* Convert logical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertLogical( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +#ifdef __QNXNTO__ +/* Convert physical address to hardware specific address. */ +gceSTATUS +gckHARDWARE_ConvertPhysical( + IN gckHARDWARE Hardware, + IN gctPHYS_ADDR Physical, + OUT gctUINT32 * Address + ); +#endif + +/* Interrupt manager. */ +gceSTATUS +gckHARDWARE_Interrupt( + IN gckHARDWARE Hardware, + IN gctBOOL InterruptValid + ); + +/* Program MMU. */ +gceSTATUS +gckHARDWARE_SetMMU( + IN gckHARDWARE Hardware, + IN gctPOINTER Logical + ); + +/* Flush the MMU. */ +gceSTATUS +gckHARDWARE_FlushMMU( + IN gckHARDWARE Hardware + ); + +/* Set the page table base address. */ +gceSTATUS +gckHARDWARE_SetMMUv2( + IN gckHARDWARE Hardware, + IN gctBOOL Enable, + IN gctPOINTER MtlbAddress, + IN gceMMU_MODE Mode, + IN gctPOINTER SafeAddress, + IN gctBOOL FromPower + ); + +/* Get idle register. */ +gceSTATUS +gckHARDWARE_GetIdle( + IN gckHARDWARE Hardware, + IN gctBOOL Wait, + OUT gctUINT32 * Data + ); + +/* Flush the caches. */ +gceSTATUS +gckHARDWARE_Flush( + IN gckHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Enable/disable fast clear. */ +gceSTATUS +gckHARDWARE_SetFastClear( + IN gckHARDWARE Hardware, + IN gctINT Enable, + IN gctINT Compression + ); + +gceSTATUS +gckHARDWARE_ReadInterrupt( + IN gckHARDWARE Hardware, + OUT gctUINT32_PTR IDs + ); + +/* Power management. */ +gceSTATUS +gckHARDWARE_SetPowerManagementState( + IN gckHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gckHARDWARE_QueryPowerManagementState( + IN gckHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ); + +#if gcdPOWEROFF_TIMEOUT +gceSTATUS +gckHARDWARE_SetPowerOffTimeout( + IN gckHARDWARE Hardware, + IN gctUINT32 Timeout +); + +gceSTATUS +gckHARDWARE_QueryPowerOffTimeout( + IN gckHARDWARE Hardware, + OUT gctUINT32* Timeout +); +#endif + +/* Profile 2D Engine. */ +gceSTATUS +gckHARDWARE_ProfileEngine2D( + IN gckHARDWARE Hardware, + OUT gcs2D_PROFILE_PTR Profile + ); + +gceSTATUS +gckHARDWARE_InitializeHardware( + IN gckHARDWARE Hardware + ); + +gceSTATUS +gckHARDWARE_Reset( + IN gckHARDWARE Hardware + ); + +typedef gceSTATUS (*gctISRMANAGERFUNC)(gctPOINTER Context); + +gceSTATUS +gckHARDWARE_SetIsrManager( + IN gckHARDWARE Hardware, + IN gctISRMANAGERFUNC StartIsr, + IN gctISRMANAGERFUNC StopIsr, + IN gctPOINTER Context + ); + +/* Start a composition. */ +gceSTATUS +gckHARDWARE_Compose( + IN gckHARDWARE Hardware, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Offset, + IN gctSIZE_T Size, + IN gctUINT8 EventID + ); + +/* Check for Hardware features. */ +gceSTATUS +gckHARDWARE_IsFeatureAvailable( + IN gckHARDWARE Hardware, + IN gceFEATURE Feature + ); + +#if !gcdENABLE_VG +/******************************************************************************\ +***************************** gckINTERRUPT Object ****************************** +\******************************************************************************/ + +typedef struct _gckINTERRUPT * gckINTERRUPT; + +typedef gceSTATUS (* gctINTERRUPT_HANDLER)( + IN gckKERNEL Kernel + ); + +gceSTATUS +gckINTERRUPT_Construct( + IN gckKERNEL Kernel, + OUT gckINTERRUPT * Interrupt + ); + +gceSTATUS +gckINTERRUPT_Destroy( + IN gckINTERRUPT Interrupt + ); + +gceSTATUS +gckINTERRUPT_SetHandler( + IN gckINTERRUPT Interrupt, + IN OUT gctINT32_PTR Id, + IN gctINTERRUPT_HANDLER Handler + ); + +gceSTATUS +gckINTERRUPT_Notify( + IN gckINTERRUPT Interrupt, + IN gctBOOL Valid + ); +#endif +/******************************************************************************\ +******************************** gckEVENT Object ******************************* +\******************************************************************************/ + +typedef struct _gckEVENT * gckEVENT; + +/* Construct a new gckEVENT object. */ +gceSTATUS +gckEVENT_Construct( + IN gckKERNEL Kernel, + OUT gckEVENT * Event + ); + +/* Destroy an gckEVENT object. */ +gceSTATUS +gckEVENT_Destroy( + IN gckEVENT Event + ); + +/* Reserve the next available hardware event. */ +gceSTATUS +gckEVENT_GetEvent( + IN gckEVENT Event, + IN gctBOOL Wait, + OUT gctUINT8 * EventID, + IN gceKERNEL_WHERE Source + ); + +/* Add a new event to the list of events. */ +gceSTATUS +gckEVENT_AddList( + IN gckEVENT Event, + IN gcsHAL_INTERFACE_PTR Interface, + IN gceKERNEL_WHERE FromWhere, + IN gctBOOL AllocateAllowed + ); + +/* Schedule a FreeNonPagedMemory event. */ +gceSTATUS +gckEVENT_FreeNonPagedMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeContiguousMemory event. */ +gceSTATUS +gckEVENT_FreeContiguousMemory( + IN gckEVENT Event, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a FreeVideoMemory event. */ +gceSTATUS +gckEVENT_FreeVideoMemory( + IN gckEVENT Event, + IN gcuVIDMEM_NODE_PTR VideoMemory, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule a signal event. */ +gceSTATUS +gckEVENT_Signal( + IN gckEVENT Event, + IN gctSIGNAL Signal, + IN gceKERNEL_WHERE FromWhere + ); + +/* Schedule an Unlock event. */ +gceSTATUS +gckEVENT_Unlock( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere, + IN gcuVIDMEM_NODE_PTR Node, + IN gceSURF_TYPE Type + ); + +gceSTATUS +gckEVENT_CommitDone( + IN gckEVENT Event, + IN gceKERNEL_WHERE FromWhere + ); + +gceSTATUS +gckEVENT_Submit( + IN gckEVENT Event, + IN gctBOOL Wait, + IN gctBOOL FromPower + ); + +/* Commit an event queue. */ +gceSTATUS +gckEVENT_Commit( + IN gckEVENT Event, + IN gcsQUEUE_PTR Queue + ); + +/* Schedule a composition event. */ +gceSTATUS +gckEVENT_Compose( + IN gckEVENT Event, + IN gcsHAL_COMPOSE_PTR Info + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Notify( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +/* Event callback routine. */ +gceSTATUS +gckEVENT_Interrupt( + IN gckEVENT Event, + IN gctUINT32 IDs + ); + +gceSTATUS +gckEVENT_Dump( + IN gckEVENT Event + ); +/******************************************************************************\ +******************************* gckCOMMAND Object ****************************** +\******************************************************************************/ + +typedef struct _gckCOMMAND * gckCOMMAND; + +/* Construct a new gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Construct( + IN gckKERNEL Kernel, + OUT gckCOMMAND * Command + ); + +/* Destroy an gckCOMMAND object. */ +gceSTATUS +gckCOMMAND_Destroy( + IN gckCOMMAND Command + ); + +/* Acquire command queue synchronization objects. */ +gceSTATUS +gckCOMMAND_EnterCommit( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ); + +/* Release command queue synchronization objects. */ +gceSTATUS +gckCOMMAND_ExitCommit( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ); + +/* Start the command queue. */ +gceSTATUS +gckCOMMAND_Start( + IN gckCOMMAND Command + ); + +/* Stop the command queue. */ +gceSTATUS +gckCOMMAND_Stop( + IN gckCOMMAND Command, + IN gctBOOL FromRecovery + ); + +/* Commit a buffer to the command queue. */ +gceSTATUS +gckCOMMAND_Commit( + IN gckCOMMAND Command, + IN gckCONTEXT Context, + IN gcoCMDBUF CommandBuffer, + IN gcsSTATE_DELTA_PTR StateDelta, + IN gcsQUEUE_PTR EventQueue, + IN gctUINT32 ProcessID + ); + +/* Reserve space in the command buffer. */ +gceSTATUS +gckCOMMAND_Reserve( + IN gckCOMMAND Command, + IN gctSIZE_T RequestedBytes, + OUT gctPOINTER * Buffer, + OUT gctSIZE_T * BufferSize + ); + +/* Execute reserved space in the command buffer. */ +gceSTATUS +gckCOMMAND_Execute( + IN gckCOMMAND Command, + IN gctSIZE_T RequstedBytes + ); + +/* Stall the command queue. */ +gceSTATUS +gckCOMMAND_Stall( + IN gckCOMMAND Command, + IN gctBOOL FromPower + ); + +/* Attach user process. */ +gceSTATUS +gckCOMMAND_Attach( + IN gckCOMMAND Command, + OUT gckCONTEXT * Context, + OUT gctSIZE_T * StateCount, + IN gctUINT32 ProcessID + ); + +/* Detach user process. */ +gceSTATUS +gckCOMMAND_Detach( + IN gckCOMMAND Command, + IN gckCONTEXT Context + ); + +/******************************************************************************\ +********************************* gckMMU Object ******************************** +\******************************************************************************/ + +typedef struct _gckMMU * gckMMU; + +/* Construct a new gckMMU object. */ +gceSTATUS +gckMMU_Construct( + IN gckKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckMMU * Mmu + ); + +/* Destroy an gckMMU object. */ +gceSTATUS +gckMMU_Destroy( + IN gckMMU Mmu + ); + +/* Enable the MMU. */ +gceSTATUS +gckMMU_Enable( + IN gckMMU Mmu, + IN gctUINT32 PhysBaseAddr, + IN gctUINT32 PhysSize + ); + +/* Allocate pages inside the MMU. */ +gceSTATUS +gckMMU_AllocatePages( + IN gckMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ); + +/* Remove a page table from the MMU. */ +gceSTATUS +gckMMU_FreePages( + IN gckMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ); + +/* Set the MMU page with info. */ +gceSTATUS +gckMMU_SetPage( + IN gckMMU Mmu, + IN gctUINT32 PageAddress, + IN gctUINT32 *PageEntry + ); + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_InsertNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); + +gceSTATUS +gckMMU_RemoveNode( + IN gckMMU Mmu, + IN gcuVIDMEM_NODE_PTR Node); +#endif + +#ifdef __QNXNTO__ +gceSTATUS +gckMMU_FreeHandleMemory( + IN gckKERNEL Kernel, + IN gckMMU Mmu, + IN gctUINT32 Pid + ); +#endif + +gceSTATUS +gckMMU_Flush( + IN gckMMU Mmu + ); + + +#if VIVANTE_PROFILER +gceSTATUS +gckHARDWARE_QueryProfileRegisters( + IN gckHARDWARE Hardware, + OUT gcsPROFILER_COUNTERS * Counters + ); +#endif + + + +#ifdef __cplusplus +} +#endif + +#if gcdENABLE_VG +#include "gc_hal_vg.h" +#endif + +#endif /* __gc_hal_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_base.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_base.h new file mode 100644 index 0000000..72e23ad --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_base.h @@ -0,0 +1,3612 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_base_h_ +#define __gc_hal_base_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" + +#include "gc_hal_dump.h" +#include "gc_hal_md5.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gckOS * gckOS; +typedef struct _gcoHAL * gcoHAL; +typedef struct _gcoOS * gcoOS; +typedef struct _gco2D * gco2D; + +#ifndef VIVANTE_NO_3D +typedef struct _gco3D * gco3D; +#endif + +typedef struct _gcoSURF * gcoSURF; +typedef struct _gcsSURF_INFO * gcsSURF_INFO_PTR; +typedef struct _gcsSURF_NODE * gcsSURF_NODE_PTR; +typedef struct _gcsSURF_FORMAT_INFO * gcsSURF_FORMAT_INFO_PTR; +typedef struct _gcsPOINT * gcsPOINT_PTR; +typedef struct _gcsSIZE * gcsSIZE_PTR; +typedef struct _gcsRECT * gcsRECT_PTR; +typedef struct _gcsBOUNDARY * gcsBOUNDARY_PTR; +typedef struct _gcoDUMP * gcoDUMP; +typedef struct _gcoHARDWARE * gcoHARDWARE; +typedef union _gcuVIDMEM_NODE * gcuVIDMEM_NODE_PTR; + +#if gcdENABLE_VG +typedef struct _gcoVG * gcoVG; +typedef struct _gcsCOMPLETION_SIGNAL * gcsCOMPLETION_SIGNAL_PTR; +typedef struct _gcsCONTEXT_MAP * gcsCONTEXT_MAP_PTR; +#else +typedef void * gcoVG; +#endif + +/******************************************************************************\ +******************************* Process local storage ************************* +\******************************************************************************/ + +typedef struct _gcsPLS * gcsPLS_PTR; +typedef struct _gcsPLS +{ + /* Global objects. */ + gcoOS os; + gcoHAL hal; + + /* Internal memory pool. */ + gctSIZE_T internalSize; + gctPHYS_ADDR internalPhysical; + gctPOINTER internalLogical; + + /* External memory pool. */ + gctSIZE_T externalSize; + gctPHYS_ADDR externalPhysical; + gctPOINTER externalLogical; + + /* Contiguous memory pool. */ + gctSIZE_T contiguousSize; + gctPHYS_ADDR contiguousPhysical; + gctPOINTER contiguousLogical; + + /* EGL-specific process-wide objects. */ + gctPOINTER eglDisplayInfo; + gctPOINTER eglSurfaceInfo; +} +gcsPLS; + +extern gcsPLS gcPLS; + +/******************************************************************************\ +******************************* Thread local storage ************************* +\******************************************************************************/ + +typedef struct _gcsTLS * gcsTLS_PTR; + +typedef void (* gctTLS_DESTRUCTOR) ( + gcsTLS_PTR TLS + ); + +typedef struct _gcsTLS +{ + gceHARDWARE_TYPE currentType; + gcoHARDWARE hardware; + /* Only for separated 3D and 2D */ + gcoHARDWARE hardware2D; +#if gcdENABLE_VG + gcoVGHARDWARE vg; + gcoVG engineVG; +#endif /* gcdENABLE_VG */ + gctPOINTER context; + gctTLS_DESTRUCTOR destructor; + gctBOOL ProcessExiting; + +#ifndef VIVANTE_NO_3D + gco3D engine3D; +#endif + gco2D engine2D; +} +gcsTLS; + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +typedef enum _gcePLS_VALUE +{ + gcePLS_VALUE_EGL_DISPLAY_INFO, + gcePLS_VALUE_EGL_SURFACE_INFO +} +gcePLS_VALUE; + +/* Video memory pool type. */ +typedef enum _gcePOOL +{ + gcvPOOL_UNKNOWN = 0, + gcvPOOL_DEFAULT, + gcvPOOL_LOCAL, + gcvPOOL_LOCAL_INTERNAL, + gcvPOOL_LOCAL_EXTERNAL, + gcvPOOL_UNIFIED, + gcvPOOL_SYSTEM, + gcvPOOL_VIRTUAL, + gcvPOOL_USER, + gcvPOOL_CONTIGUOUS, + + gcvPOOL_NUMBER_OF_POOLS +} +gcePOOL; + +#ifndef VIVANTE_NO_3D +/* Blending functions. */ +typedef enum _gceBLEND_FUNCTION +{ + gcvBLEND_ZERO, + gcvBLEND_ONE, + gcvBLEND_SOURCE_COLOR, + gcvBLEND_INV_SOURCE_COLOR, + gcvBLEND_SOURCE_ALPHA, + gcvBLEND_INV_SOURCE_ALPHA, + gcvBLEND_TARGET_COLOR, + gcvBLEND_INV_TARGET_COLOR, + gcvBLEND_TARGET_ALPHA, + gcvBLEND_INV_TARGET_ALPHA, + gcvBLEND_SOURCE_ALPHA_SATURATE, + gcvBLEND_CONST_COLOR, + gcvBLEND_INV_CONST_COLOR, + gcvBLEND_CONST_ALPHA, + gcvBLEND_INV_CONST_ALPHA, +} +gceBLEND_FUNCTION; + +/* Blending modes. */ +typedef enum _gceBLEND_MODE +{ + gcvBLEND_ADD, + gcvBLEND_SUBTRACT, + gcvBLEND_REVERSE_SUBTRACT, + gcvBLEND_MIN, + gcvBLEND_MAX, +} +gceBLEND_MODE; + +/* API flags. */ +typedef enum _gceAPI +{ + gcvAPI_D3D = 0x1, + gcvAPI_OPENGL = 0x2, + gcvAPI_OPENVG = 0x3, + gcvAPI_OPENCL = 0x4, +} +gceAPI; + +/* Depth modes. */ +typedef enum _gceDEPTH_MODE +{ + gcvDEPTH_NONE, + gcvDEPTH_Z, + gcvDEPTH_W, +} +gceDEPTH_MODE; +#endif /* VIVANTE_NO_3D */ + +typedef enum _gceWHERE +{ + gcvWHERE_COMMAND, + gcvWHERE_RASTER, + gcvWHERE_PIXEL, +} +gceWHERE; + +typedef enum _gceHOW +{ + gcvHOW_SEMAPHORE = 0x1, + gcvHOW_STALL = 0x2, + gcvHOW_SEMAPHORE_STALL = 0x3, +} +gceHOW; + +typedef enum _gceSignalHandlerType +{ + gcvHANDLE_SIGFPE_WHEN_SIGNAL_CODE_IS_0 = 0x1, +} +gceSignalHandlerType; + + +#if gcdENABLE_VG +/* gcsHAL_Limits*/ +typedef struct _gcsHAL_LIMITS +{ + /* chip info */ + gceCHIPMODEL chipModel; + gctUINT32 chipRevision; + gctUINT32 featureCount; + gctUINT32 *chipFeatures; + + /* target caps */ + gctUINT32 maxWidth; + gctUINT32 maxHeight; + gctUINT32 multiTargetCount; + gctUINT32 maxSamples; + +}gcsHAL_LIMITS; +#endif + +/******************************************************************************\ +*********** Generic Memory Allocation Optimization Using Containers ************ +\******************************************************************************/ + +/* Generic container definition. */ +typedef struct _gcsCONTAINER_LINK * gcsCONTAINER_LINK_PTR; +typedef struct _gcsCONTAINER_LINK +{ + /* Points to the next container. */ + gcsCONTAINER_LINK_PTR next; +} +gcsCONTAINER_LINK; + +typedef struct _gcsCONTAINER_RECORD * gcsCONTAINER_RECORD_PTR; +typedef struct _gcsCONTAINER_RECORD +{ + gcsCONTAINER_RECORD_PTR prev; + gcsCONTAINER_RECORD_PTR next; +} +gcsCONTAINER_RECORD; + +typedef struct _gcsCONTAINER * gcsCONTAINER_PTR; +typedef struct _gcsCONTAINER +{ + gctUINT containerSize; + gctUINT recordSize; + gctUINT recordCount; + gcsCONTAINER_LINK_PTR containers; + gcsCONTAINER_RECORD freeList; + gcsCONTAINER_RECORD allocList; +} +gcsCONTAINER; + +gceSTATUS +gcsCONTAINER_Construct( + IN gcsCONTAINER_PTR Container, + gctUINT RecordsPerContainer, + gctUINT RecordSize + ); + +gceSTATUS +gcsCONTAINER_Destroy( + IN gcsCONTAINER_PTR Container + ); + +gceSTATUS +gcsCONTAINER_AllocateRecord( + IN gcsCONTAINER_PTR Container, + OUT gctPOINTER * Record + ); + +gceSTATUS +gcsCONTAINER_FreeRecord( + IN gcsCONTAINER_PTR Container, + IN gctPOINTER Record + ); + +gceSTATUS +gcsCONTAINER_FreeAll( + IN gcsCONTAINER_PTR Container + ); + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Construct a new gcoHAL object. */ +gceSTATUS +gcoHAL_Construct( + IN gctPOINTER Context, + IN gcoOS Os, + OUT gcoHAL * Hal + ); + +/* Destroy an gcoHAL object. */ +gceSTATUS +gcoHAL_Destroy( + IN gcoHAL Hal + ); + +/* Get pointer to gco2D object. */ +gceSTATUS +gcoHAL_Get2DEngine( + IN gcoHAL Hal, + OUT gco2D * Engine + ); + +#ifndef VIVANTE_NO_3D +/* Get pointer to gco3D object. */ +gceSTATUS +gcoHAL_Get3DEngine( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +gceSTATUS +gcoHAL_Query3DEngine( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +gceSTATUS +gcoHAL_Set3DEngine( + IN gcoHAL Hal, + IN gco3D Engine + ); + +gceSTATUS +gcoHAL_Get3DHardware( + IN gcoHAL Hal, + OUT gcoHARDWARE * Hardware + ); + +gceSTATUS +gcoHAL_Set3DHardware( + IN gcoHAL Hal, + IN gcoHARDWARE Hardware + ); + + +#endif /* VIVANTE_NO_3D */ + +/* Verify whether the specified feature is available in hardware. */ +gceSTATUS +gcoHAL_IsFeatureAvailable( + IN gcoHAL Hal, + IN gceFEATURE Feature + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gcoHAL_QueryChipIdentity( + IN gcoHAL Hal, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures + ); + +/* Query the minor features of the hardware. */ +gceSTATUS gcoHAL_QueryChipMinorFeatures( + IN gcoHAL Hal, + OUT gctUINT32* NumFeatures, + OUT gctUINT32* ChipMinorFeatures + ); + +/* Query the amount of video memory. */ +gceSTATUS +gcoHAL_QueryVideoMemory( + IN gcoHAL Hal, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Map video memory. */ +gceSTATUS +gcoHAL_MapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + OUT gctPOINTER * Logical + ); + +/* Unmap video memory. */ +gceSTATUS +gcoHAL_UnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a buffer mapped through its physical address. */ +gceSTATUS +gcoHAL_ScheduleUnmapMemory( + IN gcoHAL Hal, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T NumberOfBytes, + IN gctPOINTER Logical + ); + +/* Schedule an unmap of a user buffer using event mechanism. */ +gceSTATUS +gcoHAL_ScheduleUnmapUserMemory( + IN gcoHAL Hal, + IN gctPOINTER Info, + IN gctSIZE_T Size, + IN gctUINT32 Address, + IN gctPOINTER Memory + ); + +/* Commit the current command buffer. */ +gceSTATUS +gcoHAL_Commit( + IN gcoHAL Hal, + IN gctBOOL Stall + ); + +/* Query the tile capabilities. */ +gceSTATUS +gcoHAL_QueryTiled( + IN gcoHAL Hal, + OUT gctINT32 * TileWidth2D, + OUT gctINT32 * TileHeight2D, + OUT gctINT32 * TileWidth3D, + OUT gctINT32 * TileHeight3D + ); + +gceSTATUS +gcoHAL_Compact( + IN gcoHAL Hal + ); + +#if VIVANTE_PROFILER /*gcdENABLE_PROFILING*/ +gceSTATUS +gcoHAL_ProfileStart( + IN gcoHAL Hal + ); + +gceSTATUS +gcoHAL_ProfileEnd( + IN gcoHAL Hal, + IN gctCONST_STRING Title + ); +#endif + +/* Power Management */ +gceSTATUS +gcoHAL_SetPowerManagementState( + IN gcoHAL Hal, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gcoHAL_QueryPowerManagementState( + IN gcoHAL Hal, + OUT gceCHIPPOWERSTATE *State + ); + +/* Set the filter type for filter blit. */ +gceSTATUS +gcoHAL_SetFilterType( + IN gcoHAL Hal, + IN gceFILTER_TYPE FilterType + ); + +gceSTATUS +gcoHAL_GetDump( + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Call the kernel HAL layer. */ +gceSTATUS +gcoHAL_Call( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Schedule an event. */ +gceSTATUS +gcoHAL_ScheduleEvent( + IN gcoHAL Hal, + IN OUT gcsHAL_INTERFACE_PTR Interface + ); + +/* Destroy a surface. */ +gceSTATUS +gcoHAL_DestroySurface( + IN gcoHAL Hal, + IN gcoSURF Surface + ); + +/* Request a start/stop timestamp. */ +gceSTATUS +gcoHAL_SetTimer( + IN gcoHAL Hal, + IN gctUINT32 Index, + IN gctBOOL Start + ); + +/* Get Time delta from a Timer in microseconds. */ +gceSTATUS +gcoHAL_GetTimerTime( + IN gcoHAL Hal, + IN gctUINT32 Timer, + OUT gctINT32_PTR TimeDelta + ); + +/* set timeout value. */ +gceSTATUS +gcoHAL_SetTimeOut( + IN gcoHAL Hal, + IN gctUINT32 timeOut + ); + +gceSTATUS +gcoHAL_SetHardwareType( + IN gcoHAL Hal, + IN gceHARDWARE_TYPE HardwardType + ); + +gceSTATUS +gcoHAL_GetHardwareType( + IN gcoHAL Hal, + OUT gceHARDWARE_TYPE * HardwardType + ); + +gceSTATUS +gcoHAL_QueryChipCount( + IN gcoHAL Hal, + OUT gctINT32 * Count + ); + +gceSTATUS +gcoHAL_QuerySeparated3D2D( + IN gcoHAL Hal + ); + +/* Get pointer to gcoVG object. */ +gceSTATUS +gcoHAL_GetVGEngine( + IN gcoHAL Hal, + OUT gcoVG * Engine + ); + +#if gcdENABLE_VG +gceSTATUS +gcoHAL_QueryChipLimits( + IN gcoHAL Hal, + IN gctINT32 Chip, + OUT gcsHAL_LIMITS *Limits); + +gceSTATUS +gcoHAL_QueryChipFeature( + IN gcoHAL Hal, + IN gctINT32 Chip, + IN gceFEATURE Feature); + +#endif +/******************************************************************************\ +********************************** gcoOS Object ********************************* +\******************************************************************************/ + +/* Get PLS value for given key */ +gctPOINTER +gcoOS_GetPLSValue( + IN gcePLS_VALUE key + ); + +/* Set PLS value of a given key */ +void +gcoOS_SetPLSValue( + IN gcePLS_VALUE key, + OUT gctPOINTER value + ); + +/* Get access to the thread local storage. */ +gceSTATUS +gcoOS_GetTLS( + OUT gcsTLS_PTR * TLS + ); + +/* Destroy the objects associated with the current thread. */ +void +gcoOS_FreeThreadData( + IN gctBOOL ProcessExiting + ); + +/* Construct a new gcoOS object. */ +gceSTATUS +gcoOS_Construct( + IN gctPOINTER Context, + OUT gcoOS * Os + ); + +/* Destroy an gcoOS object. */ +gceSTATUS +gcoOS_Destroy( + IN gcoOS Os + ); + +/* Get the base address for the physical memory. */ +gceSTATUS +gcoOS_GetBaseAddress( + IN gcoOS Os, + OUT gctUINT32_PTR BaseAddress + ); + +/* Allocate memory from the heap. */ +gceSTATUS +gcoOS_Allocate( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Get allocated memory size. */ +gceSTATUS +gcoOS_GetMemorySize( + IN gcoOS Os, + IN gctPOINTER Memory, + OUT gctSIZE_T_PTR MemorySize + ); + +/* Free allocated memory. */ +gceSTATUS +gcoOS_Free( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate memory. */ +gceSTATUS +gcoOS_AllocateMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); + +/* Free memory. */ +gceSTATUS +gcoOS_FreeMemory( + IN gcoOS Os, + IN gctPOINTER Memory + ); + +/* Allocate contiguous memory. */ +gceSTATUS +gcoOS_AllocateContiguous( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free contiguous memory. */ +gceSTATUS +gcoOS_FreeContiguous( + IN gcoOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +#if gcdENABLE_BANK_ALIGNMENT +gceSTATUS +gcoSURF_GetBankOffsetBytes( + IN gcoSURF Surfce, + IN gceSURF_TYPE Type, + IN gctUINT32 Stride, + IN gctUINT32_PTR Bytes + ); +#endif + +/* Map user memory. */ +gceSTATUS +gcoOS_MapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ); + +/* Unmap user memory. */ +gceSTATUS +gcoOS_UnmapUserMemory( + IN gcoOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ); + +/* Device I/O Control call to the kernel HAL layer. */ +gceSTATUS +gcoOS_DeviceControl( + IN gcoOS Os, + IN gctUINT32 IoControlCode, + IN gctPOINTER InputBuffer, + IN gctSIZE_T InputBufferSize, + IN gctPOINTER OutputBuffer, + IN gctSIZE_T OutputBufferSize + ); + +/* Allocate non paged memory. */ +gceSTATUS +gcoOS_AllocateNonPagedMemory( + IN gcoOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ); + +/* Free non paged memory. */ +gceSTATUS +gcoOS_FreeNonPagedMemory( + IN gcoOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ); + +#define gcmOS_SAFE_FREE(os, mem) \ + gcoOS_Free(os, mem); \ + mem = gcvNULL + +#define gcmkOS_SAFE_FREE(os, mem) \ + gckOS_Free(os, mem); \ + mem = gcvNULL + +typedef enum _gceFILE_MODE +{ + gcvFILE_CREATE = 0, + gcvFILE_APPEND, + gcvFILE_READ, + gcvFILE_CREATETEXT, + gcvFILE_APPENDTEXT, + gcvFILE_READTEXT, +} +gceFILE_MODE; + +/* Open a file. */ +gceSTATUS +gcoOS_Open( + IN gcoOS Os, + IN gctCONST_STRING FileName, + IN gceFILE_MODE Mode, + OUT gctFILE * File + ); + +/* Close a file. */ +gceSTATUS +gcoOS_Close( + IN gcoOS Os, + IN gctFILE File + ); + +/* Read data from a file. */ +gceSTATUS +gcoOS_Read( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctPOINTER Data, + OUT gctSIZE_T * ByteRead + ); + +/* Write data to a file. */ +gceSTATUS +gcoOS_Write( + IN gcoOS Os, + IN gctFILE File, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Flush data to a file. */ +gceSTATUS +gcoOS_Flush( + IN gcoOS Os, + IN gctFILE File + ); + +/* Create an endpoint for communication. */ +gceSTATUS +gcoOS_Socket( + IN gcoOS Os, + IN gctINT Domain, + IN gctINT Type, + IN gctINT Protocol, + OUT gctINT *SockFd + ); + +/* Close a socket. */ +gceSTATUS +gcoOS_CloseSocket( + IN gcoOS Os, + IN gctINT SockFd + ); + +/* Initiate a connection on a socket. */ +gceSTATUS +gcoOS_Connect( + IN gcoOS Os, + IN gctINT SockFd, + IN gctCONST_POINTER HostName, + IN gctUINT Port); + +/* Shut down part of connection on a socket. */ +gceSTATUS +gcoOS_Shutdown( + IN gcoOS Os, + IN gctINT SockFd, + IN gctINT How + ); + +/* Send a message on a socket. */ +gceSTATUS +gcoOS_Send( + IN gcoOS Os, + IN gctINT SockFd, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data, + IN gctINT Flags + ); + +/* Initiate a connection on a socket. */ +gceSTATUS +gcoOS_WaitForSend( + IN gcoOS Os, + IN gctINT SockFd, + IN gctINT Seconds, + IN gctINT MicroSeconds); + +/* Get environment variable value. */ +gceSTATUS +gcoOS_GetEnv( + IN gcoOS Os, + IN gctCONST_STRING VarName, + OUT gctSTRING * Value + ); + +/* Get current working directory. */ +gceSTATUS +gcoOS_GetCwd( + IN gcoOS Os, + IN gctINT SizeInBytes, + OUT gctSTRING Buffer + ); + +/* Get file status info. */ +gceSTATUS +gcoOS_Stat( + IN gcoOS Os, + IN gctCONST_STRING FileName, + OUT gctPOINTER Buffer + ); + +typedef enum _gceFILE_WHENCE +{ + gcvFILE_SEEK_SET, + gcvFILE_SEEK_CUR, + gcvFILE_SEEK_END +} +gceFILE_WHENCE; + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_Seek( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Offset, + IN gceFILE_WHENCE Whence + ); + +/* Set the current position of a file. */ +gceSTATUS +gcoOS_SetPos( + IN gcoOS Os, + IN gctFILE File, + IN gctUINT32 Position + ); + +/* Get the current position of a file. */ +gceSTATUS +gcoOS_GetPos( + IN gcoOS Os, + IN gctFILE File, + OUT gctUINT32 * Position + ); + +/* Perform a memory copy. */ +gceSTATUS +gcoOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ); + +/* Perform a memory fill. */ +gceSTATUS +gcoOS_MemFill( + IN gctPOINTER Destination, + IN gctUINT8 Filler, + IN gctSIZE_T Bytes + ); + +/* Zero memory. */ +gceSTATUS +gcoOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Same as strstr. */ +gceSTATUS +gcoOS_StrStr( + IN gctCONST_STRING String, + IN gctCONST_STRING SubString, + OUT gctSTRING * Output + ); + +/* Find the last occurance of a character inside a string. */ +gceSTATUS +gcoOS_StrFindReverse( + IN gctCONST_STRING String, + IN gctINT8 Character, + OUT gctSTRING * Output + ); + +gceSTATUS +gcoOS_StrLen( + IN gctCONST_STRING String, + OUT gctSIZE_T * Length + ); + +gceSTATUS +gcoOS_StrDup( + IN gcoOS Os, + IN gctCONST_STRING String, + OUT gctSTRING * Target + ); + +/* Copy a string. */ +gceSTATUS +gcoOS_StrCopySafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Append a string. */ +gceSTATUS +gcoOS_StrCatSafe( + IN gctSTRING Destination, + IN gctSIZE_T DestinationSize, + IN gctCONST_STRING Source + ); + +/* Compare two strings. */ +gceSTATUS +gcoOS_StrCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2 + ); + +/* Compare characters of two strings. */ +gceSTATUS +gcoOS_StrNCmp( + IN gctCONST_STRING String1, + IN gctCONST_STRING String2, + IN gctSIZE_T Count + ); + +/* Convert string to float. */ +gceSTATUS +gcoOS_StrToFloat( + IN gctCONST_STRING String, + OUT gctFLOAT * Float + ); + +/* Convert hex string to integer. */ +gceSTATUS gcoOS_HexStrToInt( + IN gctCONST_STRING String, + OUT gctINT * Int + ); + +/* Convert hex string to float. */ +gceSTATUS gcoOS_HexStrToFloat( + IN gctCONST_STRING String, + OUT gctFLOAT * Float + ); + +/* Convert string to integer. */ +gceSTATUS +gcoOS_StrToInt( + IN gctCONST_STRING String, + OUT gctINT * Int + ); + +gceSTATUS +gcoOS_MemCmp( + IN gctCONST_POINTER Memory1, + IN gctCONST_POINTER Memory2, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_PrintStrSafe( + OUT gctSTRING String, + IN gctSIZE_T StringSize, + IN OUT gctUINT * Offset, + IN gctCONST_STRING Format, + ... + ); + +gceSTATUS +gcoOS_LoadLibrary( + IN gcoOS Os, + IN gctCONST_STRING Library, + OUT gctHANDLE * Handle + ); + +gceSTATUS +gcoOS_FreeLibrary( + IN gcoOS Os, + IN gctHANDLE Handle + ); + +gceSTATUS +gcoOS_GetProcAddress( + IN gcoOS Os, + IN gctHANDLE Handle, + IN gctCONST_STRING Name, + OUT gctPOINTER * Function + ); + +gceSTATUS +gcoOS_Compact( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_AddSignalHandler ( + IN gceSignalHandlerType SignalHandlerType + ); + +#if VIVANTE_PROFILER /*gcdENABLE_PROFILING*/ +gceSTATUS +gcoOS_ProfileStart( + IN gcoOS Os + ); + +gceSTATUS +gcoOS_ProfileEnd( + IN gcoOS Os, + IN gctCONST_STRING Title + ); + +gceSTATUS +gcoOS_SetProfileSetting( + IN gcoOS Os, + IN gctBOOL Enable, + IN gctCONST_STRING FileName + ); +#endif + +/* Query the video memory. */ +gceSTATUS +gcoOS_QueryVideoMemory( + IN gcoOS Os, + OUT gctPHYS_ADDR * InternalAddress, + OUT gctSIZE_T * InternalSize, + OUT gctPHYS_ADDR * ExternalAddress, + OUT gctSIZE_T * ExternalSize, + OUT gctPHYS_ADDR * ContiguousAddress, + OUT gctSIZE_T * ContiguousSize + ); + +/* Detect if the process is the executable specified. */ +gceSTATUS +gcoOS_DetectProcessByName( + IN gctCONST_STRING Name + ); + +/*----------------------------------------------------------------------------*/ +/*----- Atoms ----------------------------------------------------------------*/ + +typedef struct gcsATOM * gcsATOM_PTR; + +/* Construct an atom. */ +gceSTATUS +gcoOS_AtomConstruct( + IN gcoOS Os, + OUT gcsATOM_PTR * Atom + ); + +/* Destroy an atom. */ +gceSTATUS +gcoOS_AtomDestroy( + IN gcoOS Os, + IN gcsATOM_PTR Atom + ); + +/* Increment an atom. */ +gceSTATUS +gcoOS_AtomIncrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +/* Decrement an atom. */ +gceSTATUS +gcoOS_AtomDecrement( + IN gcoOS Os, + IN gcsATOM_PTR Atom, + OUT gctINT32_PTR OldValue + ); + +gctHANDLE +gcoOS_GetCurrentProcessID( + void + ); + +gctHANDLE +gcoOS_GetCurrentThreadID( + void + ); + +/*----------------------------------------------------------------------------*/ +/*----- Time -----------------------------------------------------------------*/ + +/* Get the number of milliseconds since the system started. */ +gctUINT32 +gcoOS_GetTicks( + void + ); + +/* Get time in microseconds. */ +gceSTATUS +gcoOS_GetTime( + gctUINT64_PTR Time + ); + +/* Get CPU usage in microseconds. */ +gceSTATUS +gcoOS_GetCPUTime( + gctUINT64_PTR CPUTime + ); + +/* Get memory usage. */ +gceSTATUS +gcoOS_GetMemoryUsage( + gctUINT32_PTR MaxRSS, + gctUINT32_PTR IxRSS, + gctUINT32_PTR IdRSS, + gctUINT32_PTR IsRSS + ); + +/* Delay a number of microseconds. */ +gceSTATUS +gcoOS_Delay( + IN gcoOS Os, + IN gctUINT32 Delay + ); + +/*----------------------------------------------------------------------------*/ +/*----- Threads --------------------------------------------------------------*/ + +#ifdef _WIN32 +/* Cannot include windows.h here becuase "near" and "far" + * which are used in gcsDEPTH_INFO, are defined to nothing in WinDef.h. + * So, use the real value of DWORD and WINAPI, instead. + * DWORD is unsigned long, and WINAPI is __stdcall. + * If these two are change in WinDef.h, the following two typdefs + * need to be changed, too. + */ +typedef unsigned long gctTHREAD_RETURN; +typedef unsigned long (__stdcall * gcTHREAD_ROUTINE)(void * Argument); +#else +typedef void * gctTHREAD_RETURN; +typedef void * (* gcTHREAD_ROUTINE)(void *); +#endif + +/* Create a new thread. */ +gceSTATUS +gcoOS_CreateThread( + IN gcoOS Os, + IN gcTHREAD_ROUTINE Worker, + IN gctPOINTER Argument, + OUT gctPOINTER * Thread + ); + +/* Close a thread. */ +gceSTATUS +gcoOS_CloseThread( + IN gcoOS Os, + IN gctPOINTER Thread + ); + +/*----------------------------------------------------------------------------*/ +/*----- Mutexes --------------------------------------------------------------*/ + +/* Create a new mutex. */ +gceSTATUS +gcoOS_CreateMutex( + IN gcoOS Os, + OUT gctPOINTER * Mutex + ); + +/* Delete a mutex. */ +gceSTATUS +gcoOS_DeleteMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/* Acquire a mutex. */ +gceSTATUS +gcoOS_AcquireMutex( + IN gcoOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ); + +/* Release a mutex. */ +gceSTATUS +gcoOS_ReleaseMutex( + IN gcoOS Os, + IN gctPOINTER Mutex + ); + +/*----------------------------------------------------------------------------*/ +/*----- Signals --------------------------------------------------------------*/ + +/* Create a signal. */ +gceSTATUS +gcoOS_CreateSignal( + IN gcoOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ); + +/* Destroy a signal. */ +gceSTATUS +gcoOS_DestroySignal( + IN gcoOS Os, + IN gctSIGNAL Signal + ); + +/* Signal a signal. */ +gceSTATUS +gcoOS_Signal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ); + +/* Wait for a signal. */ +gceSTATUS +gcoOS_WaitSignal( + IN gcoOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ); + +/* Map a signal from another process */ +gceSTATUS +gcoOS_MapSignal( + IN gctSIGNAL RemoteSignal, + OUT gctSIGNAL * LocalSignal + ); + +/* Unmap a signal mapped from another process */ +gceSTATUS +gcoOS_UnmapSignal( + IN gctSIGNAL Signal + ); + +/* Write a register. */ +gceSTATUS +gcoOS_WriteRegister( + IN gcoOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ); + +/* Read a register. */ +gceSTATUS +gcoOS_ReadRegister( + IN gcoOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ); + +gceSTATUS +gcoOS_CacheClean( + IN gcoOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_CacheFlush( + IN gcoOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_CacheInvalidate( + IN gcoOS Os, + IN gcuVIDMEM_NODE_PTR Node, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoOS_MemoryBarrier( + IN gcoOS Os, + IN gctPOINTER Logical + ); + + +/*----------------------------------------------------------------------------*/ +/*----- Profile --------------------------------------------------------------*/ + +gceSTATUS +gckOS_GetProfileTick( + OUT gctUINT64_PTR Tick + ); + +gceSTATUS +gckOS_QueryProfileTickRate( + OUT gctUINT64_PTR TickRate + ); + +gctUINT32 +gckOS_ProfileToMS( + IN gctUINT64 Ticks + ); + +gceSTATUS +gcoOS_GetProfileTick( + OUT gctUINT64_PTR Tick + ); + +gceSTATUS +gcoOS_QueryProfileTickRate( + OUT gctUINT64_PTR TickRate + ); + +#define _gcmPROFILE_INIT(prefix, freq, start) \ + do { \ + prefix ## OS_QueryProfileTickRate(&(freq)); \ + prefix ## OS_GetProfileTick(&(start)); \ + } while (gcvFALSE) + +#define _gcmPROFILE_QUERY(prefix, start, ticks) \ + do { \ + prefix ## OS_GetProfileTick(&(ticks)); \ + (ticks) = ((ticks) > (start)) ? ((ticks) - (start)) \ + : (~0ull - (start) + (ticks) + 1); \ + } while (gcvFALSE) + +#if gcdENABLE_PROFILING +# define gcmkPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gck, freq, start) +# define gcmkPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gck, start, ticks) +# define gcmPROFILE_INIT(freq, start) _gcmPROFILE_INIT(gco, freq, start) +# define gcmPROFILE_QUERY(start, ticks) _gcmPROFILE_QUERY(gco, start, ticks) +# define gcmPROFILE_ONLY(x) x +# define gcmPROFILE_ELSE(x) do { } while (gcvFALSE) +# define gcmPROFILE_DECLARE_ONLY(x) x +# define gcmPROFILE_DECLARE_ELSE(x) typedef x +#else +# define gcmkPROFILE_INIT(start, freq) do { } while (gcvFALSE) +# define gcmkPROFILE_QUERY(start, ticks) do { } while (gcvFALSE) +# define gcmPROFILE_INIT(start, freq) do { } while (gcvFALSE) +# define gcmPROFILE_QUERY(start, ticks) do { } while (gcvFALSE) +# define gcmPROFILE_ONLY(x) do { } while (gcvFALSE) +# define gcmPROFILE_ELSE(x) x +# define gcmPROFILE_DECLARE_ONLY(x) typedef x +# define gcmPROFILE_DECLARE_ELSE(x) x +#endif + +/******************************************************************************* +** gcoMATH object +*/ + +#define gcdPI 3.14159265358979323846f + +/* Kernel. */ +gctINT +gckMATH_ModuloInt( + IN gctINT X, + IN gctINT Y + ); + +/* User. */ +gctUINT32 +gcoMATH_Log2in5dot5( + IN gctINT X + ); + + +gctFLOAT +gcoMATH_UIntAsFloat( + IN gctUINT32 X + ); + +gctUINT32 +gcoMATH_FloatAsUInt( + IN gctFLOAT X + ); + +gctBOOL +gcoMATH_CompareEqualF( + IN gctFLOAT X, + IN gctFLOAT Y + ); + +gctUINT16 +gcoMATH_UInt8AsFloat16( + IN gctUINT8 X + ); + +/******************************************************************************\ +**************************** Coordinate Structures ***************************** +\******************************************************************************/ + +typedef struct _gcsPOINT +{ + gctINT32 x; + gctINT32 y; +} +gcsPOINT; + +typedef struct _gcsSIZE +{ + gctINT32 width; + gctINT32 height; +} +gcsSIZE; + +typedef struct _gcsRECT +{ + gctINT32 left; + gctINT32 top; + gctINT32 right; + gctINT32 bottom; +} +gcsRECT; + + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*------------------------------- gcoSURF Common ------------------------------*/ + +/* Color format classes. */ +typedef enum _gceFORMAT_CLASS +{ + gcvFORMAT_CLASS_RGBA = 4500, + gcvFORMAT_CLASS_YUV, + gcvFORMAT_CLASS_INDEX, + gcvFORMAT_CLASS_LUMINANCE, + gcvFORMAT_CLASS_BUMP, + gcvFORMAT_CLASS_DEPTH, +} +gceFORMAT_CLASS; + +/* Special enums for width field in gcsFORMAT_COMPONENT. */ +typedef enum _gceCOMPONENT_CONTROL +{ + gcvCOMPONENT_NOTPRESENT = 0x00, + gcvCOMPONENT_DONTCARE = 0x80, + gcvCOMPONENT_WIDTHMASK = 0x7F, + gcvCOMPONENT_ODD = 0x80 +} +gceCOMPONENT_CONTROL; + +/* Color format component parameters. */ +typedef struct _gcsFORMAT_COMPONENT +{ + gctUINT8 start; + gctUINT8 width; +} +gcsFORMAT_COMPONENT; + +/* RGBA color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_RGBA +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT red; + gcsFORMAT_COMPONENT green; + gcsFORMAT_COMPONENT blue; +} +gcsFORMAT_CLASS_TYPE_RGBA; + +/* YUV color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_YUV +{ + gcsFORMAT_COMPONENT y; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT v; +} +gcsFORMAT_CLASS_TYPE_YUV; + +/* Index color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_INDEX +{ + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_INDEX; + +/* Luminance color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_LUMINANCE +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT value; +} +gcsFORMAT_CLASS_TYPE_LUMINANCE; + +/* Bump map color format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_BUMP +{ + gcsFORMAT_COMPONENT alpha; + gcsFORMAT_COMPONENT l; + gcsFORMAT_COMPONENT v; + gcsFORMAT_COMPONENT u; + gcsFORMAT_COMPONENT q; + gcsFORMAT_COMPONENT w; +} +gcsFORMAT_CLASS_TYPE_BUMP; + +/* Depth and stencil format class. */ +typedef struct _gcsFORMAT_CLASS_TYPE_DEPTH +{ + gcsFORMAT_COMPONENT depth; + gcsFORMAT_COMPONENT stencil; +} +gcsFORMAT_CLASS_TYPE_DEPTH; + +/* Format parameters. */ +typedef struct _gcsSURF_FORMAT_INFO +{ + /* Format code and class. */ + gceSURF_FORMAT format; + gceFORMAT_CLASS fmtClass; + + /* The size of one pixel in bits. */ + gctUINT8 bitsPerPixel; + + /* Component swizzle. */ + gceSURF_SWIZZLE swizzle; + + /* Some formats have two neighbour pixels interleaved together. */ + /* To describe such format, set the flag to 1 and add another */ + /* like this one describing the odd pixel format. */ + gctUINT8 interleaved; + + /* Format components. */ + union + { + gcsFORMAT_CLASS_TYPE_BUMP bump; + gcsFORMAT_CLASS_TYPE_RGBA rgba; + gcsFORMAT_CLASS_TYPE_YUV yuv; + gcsFORMAT_CLASS_TYPE_LUMINANCE lum; + gcsFORMAT_CLASS_TYPE_INDEX index; + gcsFORMAT_CLASS_TYPE_DEPTH depth; + } u; +} +gcsSURF_FORMAT_INFO; + +/* Frame buffer information. */ +typedef struct _gcsSURF_FRAMEBUFFER +{ + gctPOINTER logical; + gctUINT width, height; + gctINT stride; + gceSURF_FORMAT format; +} +gcsSURF_FRAMEBUFFER; + +typedef struct _gcsVIDMEM_NODE_SHARED_INFO +{ + gctBOOL tileStatusDisabled; + gcsPOINT SrcOrigin; + gcsPOINT DestOrigin; + gcsSIZE RectSize; + gctUINT32 clearValue; +} +gcsVIDMEM_NODE_SHARED_INFO; + +/* Generic pixel component descriptors. */ +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XXX8; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_XX8X; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_X8XX; +extern gcsFORMAT_COMPONENT gcvPIXEL_COMP_8XXX; + +typedef enum _gceORIENTATION +{ + gcvORIENTATION_TOP_BOTTOM, + gcvORIENTATION_BOTTOM_TOP, +} +gceORIENTATION; + + +/* Construct a new gcoSURF object. */ +gceSTATUS +gcoSURF_Construct( + IN gcoHAL Hal, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +/* Destroy an gcoSURF object. */ +gceSTATUS +gcoSURF_Destroy( + IN gcoSURF Surface + ); + +/* Map user-allocated surface. */ +gceSTATUS +gcoSURF_MapUserSurface( + IN gcoSURF Surface, + IN gctUINT Alignment, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Query vid mem node info. */ +gceSTATUS +gcoSURF_QueryVidMemNode( + IN gcoSURF Surface, + OUT gcuVIDMEM_NODE_PTR * Node, + OUT gcePOOL * Pool, + OUT gctUINT_PTR Bytes + ); + +/* Set usage attribute of a surface. */ +gceSTATUS +gcoSURF_SetUsage( + IN gcoSURF Surface, + IN gceSURF_USAGE Usage + ); + +/* Return usage attribute of a surface. */ +gceSTATUS +gcoSURF_QueryUsage( + IN gcoSURF Surface, + OUT gceSURF_USAGE *Usage + ); + +/* Set the color type of the surface. */ +gceSTATUS +gcoSURF_SetColorType( + IN gcoSURF Surface, + IN gceSURF_COLOR_TYPE ColorType + ); + +/* Get the color type of the surface. */ +gceSTATUS +gcoSURF_GetColorType( + IN gcoSURF Surface, + OUT gceSURF_COLOR_TYPE *ColorType + ); + +/* Set the surface ration angle. */ +gceSTATUS +gcoSURF_SetRotation( + IN gcoSURF Surface, + IN gceSURF_ROTATION Rotation + ); + +gceSTATUS +gcoSURF_IsValid( + IN gcoSURF Surface + ); + +#ifndef VIVANTE_NO_3D +/* Verify and return the state of the tile status mechanism. */ +gceSTATUS +gcoSURF_IsTileStatusSupported( + IN gcoSURF Surface + ); + +/* Process tile status for the specified surface. */ +gceSTATUS +gcoSURF_SetTileStatus( + IN gcoSURF Surface + ); + +/* Enable tile status for the specified surface. */ +gceSTATUS +gcoSURF_EnableTileStatus( + IN gcoSURF Surface + ); + +/* Disable tile status for the specified surface. */ +gceSTATUS +gcoSURF_DisableTileStatus( + IN gcoSURF Surface, + IN gctBOOL Decompress + ); +#endif /* VIVANTE_NO_3D */ + +/* Get surface size. */ +gceSTATUS +gcoSURF_GetSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctUINT * Depth + ); + +/* Get surface aligned sizes. */ +gceSTATUS +gcoSURF_GetAlignedSize( + IN gcoSURF Surface, + OUT gctUINT * Width, + OUT gctUINT * Height, + OUT gctINT * Stride + ); + +/* Get alignments. */ +gceSTATUS +gcoSURF_GetAlignment( + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + OUT gctUINT * AddressAlignment, + OUT gctUINT * XAlignment, + OUT gctUINT * YAlignment + ); + +/* Get surface type and format. */ +gceSTATUS +gcoSURF_GetFormat( + IN gcoSURF Surface, + OUT gceSURF_TYPE * Type, + OUT gceSURF_FORMAT * Format + ); + +/* Get surface tiling. */ +gceSTATUS +gcoSURF_GetTiling( + IN gcoSURF Surface, + OUT gceTILING * Tiling + ); + +/* Lock the surface. */ +gceSTATUS +gcoSURF_Lock( + IN gcoSURF Surface, + IN OUT gctUINT32 * Address, + IN OUT gctPOINTER * Memory + ); + +/* Unlock the surface. */ +gceSTATUS +gcoSURF_Unlock( + IN gcoSURF Surface, + IN gctPOINTER Memory + ); + +/* Return pixel format parameters. */ +gceSTATUS +gcoSURF_QueryFormat( + IN gceSURF_FORMAT Format, + OUT gcsSURF_FORMAT_INFO_PTR * Info + ); + +/* Compute the color pixel mask. */ +gceSTATUS +gcoSURF_ComputeColorMask( + IN gcsSURF_FORMAT_INFO_PTR Format, + OUT gctUINT32_PTR ColorMask + ); + +/* Flush the surface. */ +gceSTATUS +gcoSURF_Flush( + IN gcoSURF Surface + ); + +/* Fill surface from it's tile status buffer. */ +gceSTATUS +gcoSURF_FillFromTile( + IN gcoSURF Surface + ); + +/* Fill surface with a value. */ +gceSTATUS +gcoSURF_Fill( + IN gcoSURF Surface, + IN gcsPOINT_PTR Origin, + IN gcsSIZE_PTR Size, + IN gctUINT32 Value, + IN gctUINT32 Mask + ); + +/* Alpha blend two surfaces together. */ +gceSTATUS +gcoSURF_Blend( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrig, + IN gcsPOINT_PTR DestOrigin, + IN gcsSIZE_PTR Size, + IN gceSURF_BLEND_MODE Mode + ); + +/* Create a new gcoSURF wrapper object. */ +gceSTATUS +gcoSURF_ConstructWrapper( + IN gcoHAL Hal, + OUT gcoSURF * Surface + ); + +/* Set the underlying buffer for the surface wrapper. */ +gceSTATUS +gcoSURF_SetBuffer( + IN gcoSURF Surface, + IN gceSURF_TYPE Type, + IN gceSURF_FORMAT Format, + IN gctUINT Stride, + IN gctPOINTER Logical, + IN gctUINT32 Physical + ); + +/* Set the size of the surface in pixels and map the underlying buffer. */ +gceSTATUS +gcoSURF_SetWindow( + IN gcoSURF Surface, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height + ); + +/* Increase reference count of the surface. */ +gceSTATUS +gcoSURF_ReferenceSurface( + IN gcoSURF Surface + ); + +/* Get surface reference count. */ +gceSTATUS +gcoSURF_QueryReferenceCount( + IN gcoSURF Surface, + OUT gctINT32 * ReferenceCount + ); + +/* Set surface orientation. */ +gceSTATUS +gcoSURF_SetOrientation( + IN gcoSURF Surface, + IN gceORIENTATION Orientation + ); + +/* Query surface orientation. */ +gceSTATUS +gcoSURF_QueryOrientation( + IN gcoSURF Surface, + OUT gceORIENTATION * Orientation + ); + +gceSTATUS +gcoSURF_SetOffset( + IN gcoSURF Surface, + IN gctUINT Offset + ); + +gceSTATUS +gcoSURF_NODE_Cache( + IN gcsSURF_NODE_PTR Node, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes, + IN gceCACHEOPERATION Operation + ); + +/* Perform CPU cache operation on surface */ +gceSTATUS +gcoSURF_CPUCacheOperation( + IN gcoSURF Surface, + IN gceCACHEOPERATION Operation + ); + + +gceSTATUS +gcoSURF_SetLinearResolveAddress( + IN gcoSURF Surface, + IN gctUINT32 Address, + IN gctPOINTER Memory + ); +/******************************************************************************\ +********************************* gcoDUMP Object ******************************** +\******************************************************************************/ + +/* Construct a new gcoDUMP object. */ +gceSTATUS +gcoDUMP_Construct( + IN gcoOS Os, + IN gcoHAL Hal, + OUT gcoDUMP * Dump + ); + +/* Destroy a gcoDUMP object. */ +gceSTATUS +gcoDUMP_Destroy( + IN gcoDUMP Dump + ); + +/* Enable/disable dumping. */ +gceSTATUS +gcoDUMP_Control( + IN gcoDUMP Dump, + IN gctSTRING FileName + ); + +gceSTATUS +gcoDUMP_IsEnabled( + IN gcoDUMP Dump, + OUT gctBOOL * Enabled + ); + +/* Add surface. */ +gceSTATUS +gcoDUMP_AddSurface( + IN gcoDUMP Dump, + IN gctINT32 Width, + IN gctINT32 Height, + IN gceSURF_FORMAT PixelFormat, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount + ); + +/* Mark the beginning of a frame. */ +gceSTATUS +gcoDUMP_FrameBegin( + IN gcoDUMP Dump + ); + +/* Mark the end of a frame. */ +gceSTATUS +gcoDUMP_FrameEnd( + IN gcoDUMP Dump + ); + +/* Dump data. */ +gceSTATUS +gcoDUMP_DumpData( + IN gcoDUMP Dump, + IN gceDUMP_TAG Type, + IN gctUINT32 Address, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Delete an address. */ +gceSTATUS +gcoDUMP_Delete( + IN gcoDUMP Dump, + IN gctUINT32 Address + ); + + +/******************************************************************************\ +******************************* gcsRECT Structure ****************************** +\******************************************************************************/ + +/* Initialize rectangle structure. */ +gceSTATUS +gcsRECT_Set( + OUT gcsRECT_PTR Rect, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Return the width of the rectangle. */ +gceSTATUS +gcsRECT_Width( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Width + ); + +/* Return the height of the rectangle. */ +gceSTATUS +gcsRECT_Height( + IN gcsRECT_PTR Rect, + OUT gctINT32 * Height + ); + +/* Ensure that top left corner is to the left and above the right bottom. */ +gceSTATUS +gcsRECT_Normalize( + IN OUT gcsRECT_PTR Rect + ); + +/* Compare two rectangles. */ +gceSTATUS +gcsRECT_IsEqual( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * Equal + ); + +/* Compare the sizes of two rectangles. */ +gceSTATUS +gcsRECT_IsOfEqualSize( + IN gcsRECT_PTR Rect1, + IN gcsRECT_PTR Rect2, + OUT gctBOOL * EqualSize + ); + +gceSTATUS +gcsRECT_RelativeRotation( + IN gceSURF_ROTATION Orientation, + IN OUT gceSURF_ROTATION *Relation); + +gceSTATUS + +gcsRECT_Rotate( + + IN OUT gcsRECT_PTR Rect, + + IN gceSURF_ROTATION Rotation, + + IN gceSURF_ROTATION toRotation, + + IN gctINT32 SurfaceWidth, + + IN gctINT32 SurfaceHeight + + ); + +/******************************************************************************\ +**************************** gcsBOUNDARY Structure ***************************** +\******************************************************************************/ + +typedef struct _gcsBOUNDARY +{ + gctINT x; + gctINT y; + gctINT width; + gctINT height; +} +gcsBOUNDARY; + +/******************************************************************************\ +********************************* gcoHEAP Object ******************************** +\******************************************************************************/ + +typedef struct _gcoHEAP * gcoHEAP; + +/* Construct a new gcoHEAP object. */ +gceSTATUS +gcoHEAP_Construct( + IN gcoOS Os, + IN gctSIZE_T AllocationSize, + OUT gcoHEAP * Heap + ); + +/* Destroy an gcoHEAP object. */ +gceSTATUS +gcoHEAP_Destroy( + IN gcoHEAP Heap + ); + +/* Allocate memory. */ +gceSTATUS +gcoHEAP_Allocate( + IN gcoHEAP Heap, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcoHEAP_GetMemorySize( + IN gcoHEAP Heap, + IN gctPOINTER Memory, + OUT gctSIZE_T_PTR MemorySize + ); + +/* Free memory. */ +gceSTATUS +gcoHEAP_Free( + IN gcoHEAP Heap, + IN gctPOINTER Node + ); + +#if (VIVANTE_PROFILER /*gcdENABLE_PROFILING*/ || gcdDEBUG) +/* Profile the heap. */ +gceSTATUS +gcoHEAP_ProfileStart( + IN gcoHEAP Heap + ); + +gceSTATUS +gcoHEAP_ProfileEnd( + IN gcoHEAP Heap, + IN gctCONST_STRING Title + ); +#endif + + +/******************************************************************************\ +******************************* Debugging Macros ******************************* +\******************************************************************************/ + +void +gcoOS_SetDebugLevel( + IN gctUINT32 Level + ); + +void +gcoOS_GetDebugLevel( + OUT gctUINT32_PTR DebugLevel + ); + +void +gcoOS_SetDebugZone( + IN gctUINT32 Zone + ); + +void +gcoOS_GetDebugZone( + IN gctUINT32 Zone, + OUT gctUINT32_PTR DebugZone + ); + +void +gcoOS_SetDebugLevelZone( + IN gctUINT32 Level, + IN gctUINT32 Zone + ); + +void +gcoOS_SetDebugZones( + IN gctUINT32 Zones, + IN gctBOOL Enable + ); + +void +gcoOS_SetDebugFile( + IN gctCONST_STRING FileName + ); + +gctFILE +gcoOS_ReplaceDebugFile( + IN gctFILE fp + ); + +/******************************************************************************* +** +** gcmFATAL +** +** Print a message to the debugger and execute a break point. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugFatal( + IN gctCONST_STRING Message, + ... + ); + +#if gcmIS_DEBUG(gcdDEBUG_FATAL) +# define gcmFATAL gcoOS_DebugFatal +# define gcmkFATAL gckOS_DebugFatal +#elif gcdHAS_ELLIPSES +# define gcmFATAL(...) +# define gcmkFATAL(...) +#else + gcmINLINE static void + __dummy_fatal( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmFATAL __dummy_fatal +# define gcmkFATAL __dummy_fatal +#endif + +#define gcmENUM2TEXT(e) case e: return #e + +/******************************************************************************* +** +** gcmTRACE +** +** Print a message to the debugfer if the correct level has been set. In +** retail mode this macro does nothing. +** +** ARGUMENTS: +** +** level Level of message. +** message Message. +** ... Optional arguments. +*/ +#define gcvLEVEL_NONE -1 +#define gcvLEVEL_ERROR 0 +#define gcvLEVEL_WARNING 1 +#define gcvLEVEL_INFO 2 +#define gcvLEVEL_VERBOSE 3 + +void +gckOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); + +void +gckOS_DebugTraceN( + IN gctUINT32 Level, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugTrace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) +# define gcmTRACE gcoOS_DebugTrace +# define gcmkTRACE gckOS_DebugTrace +# define gcmkTRACE_N gckOS_DebugTraceN +#elif gcdHAS_ELLIPSES +# define gcmTRACE(...) +# define gcmkTRACE(...) +# define gcmkTRACE_N(...) +#else + gcmINLINE static void + __dummy_trace( + IN gctUINT32 Level, + IN gctCONST_STRING Message, + ... + ) + { + } + + gcmINLINE static void + __dummy_trace_n( + IN gctUINT32 Level, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ) + { + } + +# define gcmTRACE __dummy_trace +# define gcmkTRACE __dummy_trace +# define gcmkTRACE_N __dummy_trace_n +#endif + +/* Zones common for kernel and user. */ +#define gcvZONE_OS (1 << 0) +#define gcvZONE_HARDWARE (1 << 1) +#define gcvZONE_HEAP (1 << 2) +#define gcvZONE_SIGNAL (1 << 27) + +/* Kernel zones. */ +#define gcvZONE_KERNEL (1 << 3) +#define gcvZONE_VIDMEM (1 << 4) +#define gcvZONE_COMMAND (1 << 5) +#define gcvZONE_DRIVER (1 << 6) +#define gcvZONE_CMODEL (1 << 7) +#define gcvZONE_MMU (1 << 8) +#define gcvZONE_EVENT (1 << 9) +#define gcvZONE_DEVICE (1 << 10) +#define gcvZONE_DATABASE (1 << 11) +#define gcvZONE_INTERRUPT (1 << 12) + +/* User zones. */ +#define gcvZONE_HAL (1 << 3) +#define gcvZONE_BUFFER (1 << 4) +#define gcvZONE_CONTEXT (1 << 5) +#define gcvZONE_SURFACE (1 << 6) +#define gcvZONE_INDEX (1 << 7) +#define gcvZONE_STREAM (1 << 8) +#define gcvZONE_TEXTURE (1 << 9) +#define gcvZONE_2D (1 << 10) +#define gcvZONE_3D (1 << 11) +#define gcvZONE_COMPILER (1 << 12) +#define gcvZONE_MEMORY (1 << 13) +#define gcvZONE_STATE (1 << 14) +#define gcvZONE_AUX (1 << 15) +#define gcvZONE_VERTEX (1 << 16) +#define gcvZONE_CL (1 << 17) +#define gcvZONE_COMPOSITION (1 << 17) +#define gcvZONE_VG (1 << 18) +#define gcvZONE_IMAGE (1 << 19) +#define gcvZONE_UTILITY (1 << 20) +#define gcvZONE_PARAMETERS (1 << 21) + +/* API definitions. */ +#define gcvZONE_API_HAL (1 << 28) +#define gcvZONE_API_EGL (2 << 28) +#define gcvZONE_API_ES11 (3 << 28) +#define gcvZONE_API_ES20 (4 << 28) +#define gcvZONE_API_VG11 (5 << 28) +#define gcvZONE_API_GL (6 << 28) +#define gcvZONE_API_DFB (7 << 28) +#define gcvZONE_API_GDI (8 << 28) +#define gcvZONE_API_D3D (9 << 28) + + +#define gcmZONE_GET_API(zone) ((zone) >> 28) +/*Set gcdZONE_MASE like 0x0 | gcvZONE_API_EGL +will enable print EGL module debug info*/ +#define gcdZONE_MASK 0x0FFFFFFF + +/* Handy zones. */ +#define gcvZONE_NONE 0 +#define gcvZONE_ALL 0x0FFFFFFF + +/*Dump API depth set 1 for API, 2 for API and API behavior*/ +#define gcvDUMP_API_DEPTH 1 + +/******************************************************************************* +** +** gcmTRACE_ZONE +** +** Print a message to the debugger if the correct level and zone has been +** set. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** Level Level of message. +** Zone Zone of message. +** Message Message. +** ... Optional arguments. +*/ + +void +gckOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +void +gckOS_DebugTraceZoneN( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_DebugTraceZone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ); + +#if gcmIS_DEBUG(gcdDEBUG_TRACE) +# define gcmTRACE_ZONE gcoOS_DebugTraceZone +# define gcmkTRACE_ZONE gckOS_DebugTraceZone +# define gcmkTRACE_ZONE_N gckOS_DebugTraceZoneN +#elif gcdHAS_ELLIPSES +# define gcmTRACE_ZONE(...) +# define gcmkTRACE_ZONE(...) +# define gcmkTRACE_ZONE_N(...) +#else + gcmINLINE static void + __dummy_trace_zone( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctCONST_STRING Message, + ... + ) + { + } + + gcmINLINE static void + __dummy_trace_zone_n( + IN gctUINT32 Level, + IN gctUINT32 Zone, + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ) + { + } + +# define gcmTRACE_ZONE __dummy_trace_zone +# define gcmkTRACE_ZONE __dummy_trace_zone +# define gcmkTRACE_ZONE_N __dummy_trace_zone_n +#endif + +/******************************************************************************* +** +** gcmDEBUG_ONLY +** +** Execute a statement or function only in DEBUG mode. +** +** ARGUMENTS: +** +** f Statement or function to execute. +*/ +#if gcmIS_DEBUG(gcdDEBUG_CODE) +# define gcmDEBUG_ONLY(f) f +#else +# define gcmDEBUG_ONLY(f) +#endif + +/******************************************************************************* +** +** gcmSTACK_PUSH +** gcmSTACK_POP +** gcmSTACK_DUMP +** +** Push or pop a function with entry arguments on the trace stack. +** +** ARGUMENTS: +** +** Function Name of function. +** Line Line number. +** Text Optional text. +** ... Optional arguments for text. +*/ +#if gcmIS_DEBUG(gcdDEBUG_STACK) + void + gcoOS_StackPush( + IN gctCONST_STRING Function, + IN gctINT Line, + IN gctCONST_STRING Text, + ... + ); + void + gcoOS_StackPop( + IN gctCONST_STRING Function + ); + void + gcoOS_StackDump( + void + ); +# define gcmSTACK_PUSH gcoOS_StackPush +# define gcmSTACK_POP gcoOS_StackPop +# define gcmSTACK_DUMP gcoOS_StackDump +#elif gcdHAS_ELLIPSES +# define gcmSTACK_PUSH(...) do { } while (0) +# define gcmSTACK_POP(Function) do { } while (0) +# define gcmSTACK_DUMP() do { } while (0) +#else + gcmINLINE static void + __dummy_stack_push( + IN gctCONST_STRING Function, + IN gctINT Line, + IN gctCONST_STRING Text, ... + ) + { + } +# define gcmSTACK_PUSH __dummy_stack_push +# define gcmSTACK_POP(Function) do { } while (0) +# define gcmSTACK_DUMP() do { } while (0) +#endif + +/******************************************************************************\ +******************************** Logging Macros ******************************** +\******************************************************************************/ + +#define gcdHEADER_LEVEL gcvLEVEL_VERBOSE + + +#if gcdENABLE_PROFILING +void +gcoOS_ProfileDB( + IN gctCONST_STRING Function, + IN OUT gctBOOL_PTR Initialized + ); + +#define gcmHEADER() \ + static gctBOOL __profile__initialized__ = gcvFALSE; \ + gcmSTACK_PUSH(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ + gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__) +#define gcmHEADER_ARG(...) \ + static gctBOOL __profile__initialized__ = gcvFALSE; \ + gcmSTACK_PUSH(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ + gcoOS_ProfileDB(__FUNCTION__, &__profile__initialized__) +#define gcmFOOTER() \ + gcmSTACK_POP(__FUNCTION__); \ + gcoOS_ProfileDB(__FUNCTION__, gcvNULL) +#define gcmFOOTER_NO() \ + gcmSTACK_POP(__FUNCTION__); \ + gcoOS_ProfileDB(__FUNCTION__, gcvNULL) +#define gcmFOOTER_ARG(...) \ + gcmSTACK_POP(__FUNCTION__); \ + gcoOS_ProfileDB(__FUNCTION__, gcvNULL) +#define gcmFOOTER_KILL() \ + gcmSTACK_POP(__FUNCTION__); \ + gcoOS_ProfileDB(gcvNULL, gcvNULL) + +#else /* gcdENABLE_PROFILING */ + +#if gcdHAS_ELLIPSES +#define gcmHEADER() \ + gctINT8 __user__ = 1; \ + gctINT8_PTR __user_ptr__ = &__user__; \ + gcmSTACK_PUSH(__FUNCTION__, __LINE__, gcvNULL, gcvNULL); \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) +#else + gcmINLINE static void + __dummy_header(void) + { + } +# define gcmHEADER __dummy_header +#endif + +#if gcdHAS_ELLIPSES +# define gcmHEADER_ARG(Text, ...) \ + gctINT8 __user__ = 1; \ + gctINT8_PTR __user_ptr__ = &__user__; \ + gcmSTACK_PUSH(__FUNCTION__, __LINE__, Text, __VA_ARGS__); \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_header_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmHEADER_ARG __dummy_header_arg +#endif + +#if gcdHAS_ELLIPSES +# define gcmFOOTER() \ + gcmSTACK_POP(__FUNCTION__); \ + gcmPROFILE_ONLY(gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d) [%llu,%llu]: status=%d(%s)", \ + __FUNCTION__, __LINE__, \ + __ticks__, __total__, \ + status, gcoOS_DebugStatus2Name(status))); \ + gcmPROFILE_ELSE(gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d(%s)", \ + __FUNCTION__, __LINE__, \ + status, gcoOS_DebugStatus2Name(status))); \ + *__user_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_footer(void) + { + } +# define gcmFOOTER __dummy_footer +#endif + +#if gcdHAS_ELLIPSES +#define gcmFOOTER_NO() \ + gcmSTACK_POP(__FUNCTION__); \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__); \ + *__user_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_footer_no(void) + { + } +# define gcmFOOTER_NO __dummy_footer_no +#endif + +#if gcdHAS_ELLIPSES +#define gcmFOOTER_KILL() \ + gcmSTACK_POP(__FUNCTION__); \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__); \ + *__user_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_footer_kill(void) + { + } +# define gcmFOOTER_KILL __dummy_footer_kill +#endif + +#if gcdHAS_ELLIPSES +# define gcmFOOTER_ARG(Text, ...) \ + gcmSTACK_POP(__FUNCTION__); \ + gcmTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__); \ + *__user_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_footer_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmFOOTER_ARG __dummy_footer_arg +#endif + +#endif /* gcdENABLE_PROFILING */ + +#if gcdHAS_ELLIPSES +#define gcmkHEADER() \ + gctINT8 __kernel__ = 1; \ + gctINT8_PTR __kernel_ptr__ = &__kernel__; \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d)", __FUNCTION__, __LINE__) +#else + gcmINLINE static void + __dummy_kheader(void) + { + } +# define gcmkHEADER __dummy_kheader +#endif + +#if gcdHAS_ELLIPSES +# define gcmkHEADER_ARG(Text, ...) \ + gctINT8 __kernel__ = 1; \ + gctINT8_PTR __kernel_ptr__ = &__kernel__; \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "++%s(%d): " Text, __FUNCTION__, __LINE__, __VA_ARGS__) +#else + gcmINLINE static void + __dummy_kheader_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkHEADER_ARG __dummy_kheader_arg +#endif + +#if gcdHAS_ELLIPSES +#define gcmkFOOTER() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): status=%d(%s)", \ + __FUNCTION__, __LINE__, status, gckOS_DebugStatus2Name(status)); \ + *__kernel_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_kfooter(void) + { + } +# define gcmkFOOTER __dummy_kfooter +#endif + +#if gcdHAS_ELLIPSES +#define gcmkFOOTER_NO() \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d)", __FUNCTION__, __LINE__); \ + *__kernel_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_kfooter_no(void) + { + } +# define gcmkFOOTER_NO __dummy_kfooter_no +#endif + +#if gcdHAS_ELLIPSES +# define gcmkFOOTER_ARG(Text, ...) \ + gcmkTRACE_ZONE(gcdHEADER_LEVEL, _GC_OBJ_ZONE, \ + "--%s(%d): " Text, \ + __FUNCTION__, __LINE__, __VA_ARGS__); \ + *__kernel_ptr__ -= 1 +#else + gcmINLINE static void + __dummy_kfooter_arg( + IN gctCONST_STRING Text, + ... + ) + { + } +# define gcmkFOOTER_ARG __dummy_kfooter_arg +#endif + +#define gcmOPT_VALUE(ptr) (((ptr) == gcvNULL) ? 0 : *(ptr)) +#define gcmOPT_POINTER(ptr) (((ptr) == gcvNULL) ? gcvNULL : *(ptr)) +#define gcmOPT_STRING(ptr) (((ptr) == gcvNULL) ? "(nil)" : (ptr)) + +void +gckOS_Print( + IN gctCONST_STRING Message, + ... + ); + +void +gckOS_PrintN( + IN gctUINT ArgumentSize, + IN gctCONST_STRING Message, + ... + ); + +void +gckOS_CopyPrint( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_Print( + IN gctCONST_STRING Message, + ... + ); + +#define gcmPRINT gcoOS_Print +#define gcmkPRINT gckOS_Print +#define gcmkPRINT_N gckOS_PrintN + +#if gcdPRINT_VERSION +# define gcmPRINT_VERSION() do { \ + _gcmPRINT_VERSION(gcm); \ + gcmSTACK_DUMP(); \ + } while (0) +# define gcmkPRINT_VERSION() _gcmPRINT_VERSION(gcmk) +# define _gcmPRINT_VERSION(prefix) \ + prefix##TRACE(gcvLEVEL_ERROR, \ + "Vivante HAL version %d.%d.%d build %d %s %s", \ + gcvVERSION_MAJOR, gcvVERSION_MINOR, gcvVERSION_PATCH, \ + gcvVERSION_BUILD, gcvVERSION_DATE, gcvVERSION_TIME ) +#else +# define gcmPRINT_VERSION() do { gcmSTACK_DUMP(); } while (gcvFALSE) +# define gcmkPRINT_VERSION() do { } while (gcvFALSE) +#endif + +typedef enum _gceDUMP_BUFFER +{ + gceDUMP_BUFFER_CONTEXT, + gceDUMP_BUFFER_USER, + gceDUMP_BUFFER_KERNEL, + gceDUMP_BUFFER_LINK, + gceDUMP_BUFFER_WAITLINK, + gceDUMP_BUFFER_FROM_USER, +} +gceDUMP_BUFFER; + +void +gckOS_DumpBuffer( + IN gckOS Os, + IN gctPOINTER Buffer, + IN gctUINT Size, + IN gceDUMP_BUFFER Type, + IN gctBOOL CopyMessage + ); + +#define gcmkDUMPBUFFER gckOS_DumpBuffer + +#if gcdDUMP_COMMAND +# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage) \ + gcmkDUMPBUFFER(Os, Buffer, Size, Type, CopyMessage) +#else +# define gcmkDUMPCOMMAND(Os, Buffer, Size, Type, CopyMessage) +#endif + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + +void +gckOS_DebugFlush( + gctCONST_STRING CallerName, + gctUINT LineNumber, + gctUINT32 DmaAddress + ); + +# define gcmkDEBUGFLUSH(DmaAddress) \ + gckOS_DebugFlush(__FUNCTION__, __LINE__, DmaAddress) +#else +# define gcmkDEBUGFLUSH(DmaAddress) +#endif + +/******************************************************************************* +** +** gcmDUMP_FRAMERATE +** +** Print average frame rate +** +*/ +#if gcdDUMP_FRAMERATE + gceSTATUS + gcfDumpFrameRate( + void + ); +# define gcmDUMP_FRAMERATE gcfDumpFrameRate +#elif gcdHAS_ELLIPSES +# define gcmDUMP_FRAMERATE(...) +#else + gcmINLINE static void + __dummy_dump_frame_rate( + void + ) + { + } +# define gcmDUMP_FRAMERATE __dummy_dump_frame_rate +#endif + + +/******************************************************************************* +** +** gcmDUMP +** +** Print a dump message. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP + gceSTATUS + gcfDump( + IN gcoOS Os, + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP gcfDump +#elif gcdHAS_ELLIPSES +# define gcmDUMP(...) +#else + gcmINLINE static void + __dummy_dump( + IN gcoOS Os, + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP __dummy_dump +#endif + +/******************************************************************************* +** +** gcmDUMP_DATA +** +** Add data to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP || gcdDUMP_COMMAND + gceSTATUS + gcfDumpData( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_DATA gcfDumpData +#elif gcdHAS_ELLIPSES +# define gcmDUMP_DATA(...) +#else + gcmINLINE static void + __dummy_dump_data( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_DATA __dummy_dump_data +#endif + +/******************************************************************************* +** +** gcmDUMP_BUFFER +** +** Print a buffer to the dump. +** +** ARGUMENTS: +** +** gctSTRING Tag +** Tag for dump. +** +** gctUINT32 Physical +** Physical address of buffer. +** +** gctPOINTER Logical +** Logical address of buffer. +** +** gctUINT32 Offset +** Offset into buffer. +** +** gctSIZE_T Bytes +** Number of bytes. +*/ + +#if gcdDUMP || gcdDUMP_COMMAND +gceSTATUS +gcfDumpBuffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ); +# define gcmDUMP_BUFFER gcfDumpBuffer +#elif gcdHAS_ELLIPSES +# define gcmDUMP_BUFFER(...) +#else + gcmINLINE static void + __dummy_dump_buffer( + IN gcoOS Os, + IN gctSTRING Tag, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes + ) + { + } +# define gcmDUMP_BUFFER __dummy_dump_buffer +#endif + +/******************************************************************************* +** +** gcmDUMP_API +** +** Print a dump message for a high level API prefixed by the function name. +** +** ARGUMENTS: +** +** gctSTRING Message. +** +** ... Optional arguments. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpApi( + IN gctCONST_STRING String, + ... + ); +# define gcmDUMP_API gcfDumpApi +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API(...) +#else + gcmINLINE static void + __dummy_dump_api( + IN gctCONST_STRING Message, + ... + ) + { + } +# define gcmDUMP_API __dummy_dump_api +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY +** +** Print an array of data. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Size. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArray( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ); +# define gcmDUMP_API_ARRAY gcfDumpArray +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY(...) +#else + gcmINLINE static void + __dummy_dump_api_array( + IN gctCONST_POINTER Data, + IN gctUINT32 Size + ) + { + } +# define gcmDUMP_API_ARRAY __dummy_dump_api_array +#endif + +/******************************************************************************* +** +** gcmDUMP_API_ARRAY_TOKEN +** +** Print an array of data terminated by a token. +** +** ARGUMENTS: +** +** gctUINT32_PTR Pointer to array. +** gctUINT32 Termination. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpArrayToken( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ); +# define gcmDUMP_API_ARRAY_TOKEN gcfDumpArrayToken +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_ARRAY_TOKEN(...) +#else + gcmINLINE static void + __dummy_dump_api_array_token( + IN gctCONST_POINTER Data, + IN gctUINT32 Termination + ) + { + } +# define gcmDUMP_API_ARRAY_TOKEN __dummy_dump_api_array_token +#endif + +/******************************************************************************* +** +** gcmDUMP_API_DATA +** +** Print an array of bytes. +** +** ARGUMENTS: +** +** gctCONST_POINTER Pointer to array. +** gctSIZE_T Size. +*/ +#if gcdDUMP_API + gceSTATUS + gcfDumpApiData( + IN gctCONST_POINTER Data, + IN gctSIZE_T Size + ); +# define gcmDUMP_API_DATA gcfDumpApiData +#elif gcdHAS_ELLIPSES +# define gcmDUMP_API_DATA(...) +#else + gcmINLINE static void + __dummy_dump_api_data( + IN gctCONST_POINTER Data, + IN gctSIZE_T Size + ) + { + } +# define gcmDUMP_API_DATA __dummy_dump_api_data +#endif + +/******************************************************************************* +** +** gcmTRACE_RELEASE +** +** Print a message to the shader debugger. +** +** ARGUMENTS: +** +** message Message. +** ... Optional arguments. +*/ + +#define gcmTRACE_RELEASE gcoOS_DebugShaderTrace + +void +gcoOS_DebugShaderTrace( + IN gctCONST_STRING Message, + ... + ); + +void +gcoOS_SetDebugShaderFiles( + IN gctCONST_STRING VSFileName, + IN gctCONST_STRING FSFileName + ); + +void +gcoOS_SetDebugShaderFileType( + IN gctUINT32 ShaderType + ); + +void +gcoOS_EnableDebugBuffer( + IN gctBOOL Enable + ); + +/******************************************************************************* +** +** gcmBREAK +** +** Break into the debugger. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** None. +*/ + +void +gcoOS_DebugBreak( + void + ); + +void +gckOS_DebugBreak( + void + ); + +#if gcmIS_DEBUG(gcdDEBUG_BREAK) +# define gcmBREAK gcoOS_DebugBreak +# define gcmkBREAK gckOS_DebugBreak +#else +# define gcmBREAK() +# define gcmkBREAK() +#endif + +/******************************************************************************* +** +** gcmASSERT +** +** Evaluate an expression and break into the debugger if the expression +** evaluates to false. In retail mode this macro does nothing. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcmIS_DEBUG(gcdDEBUG_ASSERT) +# define _gcmASSERT(prefix, exp) \ + do \ + { \ + if (!(exp)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ASSERT at %s(%d)", \ + __FUNCTION__, __LINE__); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + "(%s)", #exp); \ + prefix##BREAK(); \ + } \ + } \ + while (gcvFALSE) +# define gcmASSERT(exp) _gcmASSERT(gcm, exp) +# define gcmkASSERT(exp) _gcmASSERT(gcmk, exp) +#else +# define gcmASSERT(exp) +# define gcmkASSERT(exp) +#endif + +/******************************************************************************* +** +** gcmVERIFY +** +** Verify if an expression returns true. If the expression does not +** evaluates to true, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** exp Expression to evaluate. +*/ +#if gcmIS_DEBUG(gcdDEBUG_ASSERT) +# define gcmVERIFY(exp) gcmASSERT(exp) +# define gcmkVERIFY(exp) gcmkASSERT(exp) +#else +# define gcmVERIFY(exp) exp +# define gcmkVERIFY(exp) exp +#endif + +/******************************************************************************* +** +** gcmVERIFY_OK +** +** Verify a fucntion returns gcvSTATUS_OK. If the function does not return +** gcvSTATUS_OK, an assertion will happen in debug mode. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ + +void +gcoOS_Verify( + IN gceSTATUS Status + ); + +void +gckOS_Verify( + IN gceSTATUS Status + ); + +#if gcmIS_DEBUG(gcdDEBUG_ASSERT) +# define gcmVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + gcoOS_Verify(verifyStatus); \ + if (verifyStatus != gcvSTATUS_OK) \ + { \ + gcmTRACE( \ + gcvLEVEL_ERROR, \ + "gcmVERIFY_OK(%d): function returned %d", \ + __LINE__, verifyStatus \ + ); \ + } \ + gcmASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +# define gcmkVERIFY_OK(func) \ + do \ + { \ + gceSTATUS verifyStatus = func; \ + if (verifyStatus != gcvSTATUS_OK) \ + { \ + gcmkTRACE( \ + gcvLEVEL_ERROR, \ + "gcmkVERIFY_OK(%d): function returned %d", \ + __LINE__, verifyStatus \ + ); \ + } \ + gckOS_Verify(verifyStatus); \ + gcmkASSERT(verifyStatus == gcvSTATUS_OK); \ + } \ + while (gcvFALSE) +#else +# define gcmVERIFY_OK(func) func +# define gcmkVERIFY_OK(func) func +#endif + +gctCONST_STRING +gcoOS_DebugStatus2Name( + gceSTATUS status + ); + +gctCONST_STRING +gckOS_DebugStatus2Name( + gceSTATUS status + ); + +/******************************************************************************* +** +** gcmERR_BREAK +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_BREAK(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \ + status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + break; \ + } \ + do { } while (gcvFALSE) +#define _gcmkERR_BREAK(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_BREAK: status=%d(%s) @ %s(%d)", \ + status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + break; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_BREAK(func) _gcmERR_BREAK(gcm, func) +#define gcmkERR_BREAK(func) _gcmkERR_BREAK(gcmk, func) + +/******************************************************************************* +** +** gcmERR_RETURN +** +** Executes a return on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmERR_RETURN(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ + status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + prefix##FOOTER(); \ + return status; \ + } \ + do { } while (gcvFALSE) +#define _gcmkERR_RETURN(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ + status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + prefix##FOOTER(); \ + return status; \ + } \ + do { } while (gcvFALSE) +#define gcmERR_RETURN(func) _gcmERR_RETURN(gcm, func) +#define gcmkERR_RETURN(func) _gcmkERR_RETURN(gcmk, func) + + +/******************************************************************************* +** +** gcmONERROR +** +** Jump to the error handler in case there is an error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmONERROR(prefix, func) \ + do \ + { \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ONERROR: status=%d(%s) @ %s(%d)", \ + status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + goto OnError; \ + } \ + } \ + while (gcvFALSE) +#define _gcmkONERROR(prefix, func) \ + do \ + { \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ONERROR: status=%d(%s) @ %s(%d)", \ + status, gckOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + goto OnError; \ + } \ + } \ + while (gcvFALSE) +#define gcmONERROR(func) _gcmONERROR(gcm, func) +#define gcmkONERROR(func) _gcmkONERROR(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_LOCK +** +** Verifies whether the surface is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_LOCK(surfaceInfo) \ + if (!surfaceInfo->node.valid) \ + { \ + gcmONERROR(gcvSTATUS_MEMORY_UNLOCKED); \ + } \ + +/******************************************************************************* +** +** gcmVERIFY_NODE_LOCK +** +** Verifies whether the surface node is locked. +** +** ARGUMENTS: +** +** surfaceInfo Pointer to the surface iniformational structure. +*/ +#define gcmVERIFY_NODE_LOCK(surfaceNode) \ + if (!surfaceNode->valid) \ + { \ + status = gcvSTATUS_MEMORY_UNLOCKED; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmBADOBJECT_BREAK +** +** Executes a break statement on bad object. +** +** ARGUMENTS: +** +** obj Object to test. +** t Expected type of the object. +*/ +#define gcmBADOBJECT_BREAK(obj, t) \ + if ((obj == gcvNULL) \ + || (((gcsOBJECT *)(obj))->type != t) \ + ) \ + { \ + status = gcvSTATUS_INVALID_OBJECT; \ + break; \ + } \ + do { } while (gcvFALSE) + +/******************************************************************************* +** +** gcmCHECK_STATUS +** +** Executes a break statement on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** func Function to evaluate. +*/ +#define _gcmCHECK_STATUS(prefix, func) \ + do \ + { \ + last = func; \ + if (gcmIS_ERROR(last)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \ + last, gcoOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \ + status = last; \ + } \ + } \ + while (gcvFALSE) +#define _gcmkCHECK_STATUS(prefix, func) \ + do \ + { \ + last = func; \ + if (gcmIS_ERROR(last)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "CHECK_STATUS: status=%d(%s) @ %s(%d)", \ + last, gckOS_DebugStatus2Name(last), __FUNCTION__, __LINE__); \ + status = last; \ + } \ + } \ + while (gcvFALSE) +#define gcmCHECK_STATUS(func) _gcmCHECK_STATUS(gcm, func) +#define gcmkCHECK_STATUS(func) _gcmkCHECK_STATUS(gcmk, func) + +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +# define _gcmVERIFY_ARGUMENT(prefix, arg) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, #prefix "VERIFY_ARGUMENT failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); \ + return gcvSTATUS_INVALID_ARGUMENT; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) +# define gcmkVERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcmk, arg) + +/******************************************************************************* +** +** gcmDEBUG_VERIFY_ARGUMENT +** +** Works just like gcmVERIFY_ARGUMENT, but is only valid in debug mode. +** Use this to verify arguments inside non-public API functions. +*/ +#if gcdDEBUG +# define gcmDEBUG_VERIFY_ARGUMENT(arg) _gcmVERIFY_ARGUMENT(gcm, arg) +# define gcmkDEBUG_VERIFY_ARGUMENT(arg) _gcmkVERIFY_ARGUMENT(gcm, arg) +#else +# define gcmDEBUG_VERIFY_ARGUMENT(arg) +# define gcmkDEBUG_VERIFY_ARGUMENT(arg) +#endif +/******************************************************************************* +** +** gcmVERIFY_ARGUMENT_RETURN +** +** Assert if an argument does not apply to the specified expression. If +** the argument evaluates to false, gcvSTATUS_INVALID_ARGUMENT will be +** returned from the current function. In retail mode this macro does +** nothing. +** +** ARGUMENTS: +** +** arg Argument to evaluate. +*/ +# define _gcmVERIFY_ARGUMENT_RETURN(prefix, arg, value) \ + do \ + { \ + if (!(arg)) \ + { \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "gcmVERIFY_ARGUMENT_RETURN failed:"); \ + prefix##ASSERT(arg); \ + prefix##FOOTER_ARG("value=%d", value); \ + return value; \ + } \ + } \ + while (gcvFALSE) +# define gcmVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcm, arg, value) +# define gcmkVERIFY_ARGUMENT_RETURN(arg, value) \ + _gcmVERIFY_ARGUMENT_RETURN(gcmk, arg, value) + +#define MAX_LOOP_COUNT 0x7FFFFFFF + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_base_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_compiler.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_compiler.h new file mode 100644 index 0000000..ecdb763 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_compiler.h @@ -0,0 +1,3400 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file the defines the front- and back-end compilers, as well as the +** objects they use. +*/ + +#ifndef __gc_hal_compiler_h_ +#define __gc_hal_compiler_h_ + +#ifndef VIVANTE_NO_3D +#include "gc_hal_types.h" +#include "gc_hal_engine.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef GC_ENABLE_LOADTIME_OPT +#define GC_ENABLE_LOADTIME_OPT 1 +#endif + +/******************************* IR VERSION ******************/ +#define gcdSL_IR_VERSION gcmCC('\0','\0','\0','\1') + +/******************************************************************************\ +|******************************* SHADER LANGUAGE ******************************| +\******************************************************************************/ + +/* Possible shader language opcodes. */ +typedef enum _gcSL_OPCODE +{ + gcSL_NOP, /* 0x00 */ + gcSL_MOV, /* 0x01 */ + gcSL_SAT, /* 0x02 */ + gcSL_DP3, /* 0x03 */ + gcSL_DP4, /* 0x04 */ + gcSL_ABS, /* 0x05 */ + gcSL_JMP, /* 0x06 */ + gcSL_ADD, /* 0x07 */ + gcSL_MUL, /* 0x08 */ + gcSL_RCP, /* 0x09 */ + gcSL_SUB, /* 0x0A */ + gcSL_KILL, /* 0x0B */ + gcSL_TEXLD, /* 0x0C */ + gcSL_CALL, /* 0x0D */ + gcSL_RET, /* 0x0E */ + gcSL_NORM, /* 0x0F */ + gcSL_MAX, /* 0x10 */ + gcSL_MIN, /* 0x11 */ + gcSL_POW, /* 0x12 */ + gcSL_RSQ, /* 0x13 */ + gcSL_LOG, /* 0x14 */ + gcSL_FRAC, /* 0x15 */ + gcSL_FLOOR, /* 0x16 */ + gcSL_CEIL, /* 0x17 */ + gcSL_CROSS, /* 0x18 */ + gcSL_TEXLDP, /* 0x19 */ + gcSL_TEXBIAS, /* 0x1A */ + gcSL_TEXGRAD, /* 0x1B */ + gcSL_TEXLOD, /* 0x1C */ + gcSL_SIN, /* 0x1D */ + gcSL_COS, /* 0x1E */ + gcSL_TAN, /* 0x1F */ + gcSL_EXP, /* 0x20 */ + gcSL_SIGN, /* 0x21 */ + gcSL_STEP, /* 0x22 */ + gcSL_SQRT, /* 0x23 */ + gcSL_ACOS, /* 0x24 */ + gcSL_ASIN, /* 0x25 */ + gcSL_ATAN, /* 0x26 */ + gcSL_SET, /* 0x27 */ + gcSL_DSX, /* 0x28 */ + gcSL_DSY, /* 0x29 */ + gcSL_FWIDTH, /* 0x2A */ + gcSL_DIV, /* 0x2B */ + gcSL_MOD, /* 0x2C */ + gcSL_AND_BITWISE, /* 0x2D */ + gcSL_OR_BITWISE, /* 0x2E */ + gcSL_XOR_BITWISE, /* 0x2F */ + gcSL_NOT_BITWISE, /* 0x30 */ + gcSL_LSHIFT, /* 0x31 */ + gcSL_RSHIFT, /* 0x32 */ + gcSL_ROTATE, /* 0x33 */ + gcSL_BITSEL, /* 0x34 */ + gcSL_LEADZERO, /* 0x35 */ + gcSL_LOAD, /* 0x36 */ + gcSL_STORE, /* 0x37 */ + gcSL_BARRIER, /* 0x38 */ + gcSL_STORE1, /* 0x39 */ + gcSL_ATOMADD, /* 0x3A */ + gcSL_ATOMSUB, /* 0x3B */ + gcSL_ATOMXCHG, /* 0x3C */ + gcSL_ATOMCMPXCHG, /* 0x3D */ + gcSL_ATOMMIN, /* 0x3E */ + gcSL_ATOMMAX, /* 0x3F */ + gcSL_ATOMOR, /* 0x40 */ + gcSL_ATOMAND, /* 0x41 */ + gcSL_ATOMXOR, /* 0x42 */ + /*gcSL_UNUSED, 0x43 */ + /*gcSL_UNUSED, 0x44 */ + /*gcSL_UNUSED, 0x45 */ + /*gcSL_UNUSED, 0x46 */ + /*gcSL_UNUSED, 0x47 */ + /*gcSL_UNUSED, 0x48 */ + /*gcSL_UNUSED, 0x49 */ + /*gcSL_UNUSED, 0x4A */ + /*gcSL_UNUSED, 0x4B */ + /*gcSL_UNUSED, 0x4C */ + /*gcSL_UNUSED, 0x4D */ + /*gcSL_UNUSED, 0x4E */ + /*gcSL_UNUSED, 0x4F */ + /*gcSL_UNUSED, 0x50 */ + /*gcSL_UNUSED, 0x51 */ + /*gcSL_UNUSED, 0x52 */ + gcSL_ADDLO = 0x53, /* 0x53 */ /* Float only. */ + gcSL_MULLO, /* 0x54 */ /* Float only. */ + gcSL_CONV, /* 0x55 */ + gcSL_GETEXP, /* 0x56 */ + gcSL_GETMANT, /* 0x57 */ + gcSL_MULHI, /* 0x58 */ /* Integer only. */ + gcSL_CMP, /* 0x59 */ + gcSL_I2F, /* 0x5A */ + gcSL_F2I, /* 0x5B */ + gcSL_ADDSAT, /* 0x5C */ /* Integer only. */ + gcSL_SUBSAT, /* 0x5D */ /* Integer only. */ + gcSL_MULSAT, /* 0x5E */ /* Integer only. */ +} +gcSL_OPCODE; + +typedef enum _gcSL_FORMAT +{ + gcSL_FLOAT = 0, /* 0 */ + gcSL_INTEGER = 1, /* 1 */ + gcSL_INT32 = 1, /* 1 */ + gcSL_BOOLEAN = 2, /* 2 */ + gcSL_UINT32 = 3, /* 3 */ + gcSL_INT8, /* 4 */ + gcSL_UINT8, /* 5 */ + gcSL_INT16, /* 6 */ + gcSL_UINT16, /* 7 */ + gcSL_INT64, /* 8 */ /* Reserved for future enhancement. */ + gcSL_UINT64, /* 9 */ /* Reserved for future enhancement. */ + gcSL_INT128, /* 10 */ /* Reserved for future enhancement. */ + gcSL_UINT128, /* 11 */ /* Reserved for future enhancement. */ + gcSL_FLOAT16, /* 12 */ + gcSL_FLOAT64, /* 13 */ /* Reserved for future enhancement. */ + gcSL_FLOAT128, /* 14 */ /* Reserved for future enhancement. */ +} +gcSL_FORMAT; + +/* Destination write enable bits. */ +typedef enum _gcSL_ENABLE +{ + gcSL_ENABLE_NONE = 0x0, /* none is enabled, error/uninitialized state */ + gcSL_ENABLE_X = 0x1, + gcSL_ENABLE_Y = 0x2, + gcSL_ENABLE_Z = 0x4, + gcSL_ENABLE_W = 0x8, + /* Combinations. */ + gcSL_ENABLE_XY = gcSL_ENABLE_X | gcSL_ENABLE_Y, + gcSL_ENABLE_XYZ = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_XYZW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XYW = gcSL_ENABLE_X | gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_XZ = gcSL_ENABLE_X | gcSL_ENABLE_Z, + gcSL_ENABLE_XZW = gcSL_ENABLE_X | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_XW = gcSL_ENABLE_X | gcSL_ENABLE_W, + gcSL_ENABLE_YZ = gcSL_ENABLE_Y | gcSL_ENABLE_Z, + gcSL_ENABLE_YZW = gcSL_ENABLE_Y | gcSL_ENABLE_Z | gcSL_ENABLE_W, + gcSL_ENABLE_YW = gcSL_ENABLE_Y | gcSL_ENABLE_W, + gcSL_ENABLE_ZW = gcSL_ENABLE_Z | gcSL_ENABLE_W, +} +gcSL_ENABLE; + +/* Possible indices. */ +typedef enum _gcSL_INDEXED +{ + gcSL_NOT_INDEXED, /* 0 */ + gcSL_INDEXED_X, /* 1 */ + gcSL_INDEXED_Y, /* 2 */ + gcSL_INDEXED_Z, /* 3 */ + gcSL_INDEXED_W, /* 4 */ +} +gcSL_INDEXED; + +/* Opcode conditions. */ +typedef enum _gcSL_CONDITION +{ + gcSL_ALWAYS, /* 0x0 */ + gcSL_NOT_EQUAL, /* 0x1 */ + gcSL_LESS_OR_EQUAL, /* 0x2 */ + gcSL_LESS, /* 0x3 */ + gcSL_EQUAL, /* 0x4 */ + gcSL_GREATER, /* 0x5 */ + gcSL_GREATER_OR_EQUAL, /* 0x6 */ + gcSL_AND, /* 0x7 */ + gcSL_OR, /* 0x8 */ + gcSL_XOR, /* 0x9 */ + gcSL_NOT_ZERO, /* 0xA */ +} +gcSL_CONDITION; + +/* Possible source operand types. */ +typedef enum _gcSL_TYPE +{ + gcSL_NONE, /* 0x0 */ + gcSL_TEMP, /* 0x1 */ + gcSL_ATTRIBUTE, /* 0x2 */ + gcSL_UNIFORM, /* 0x3 */ + gcSL_SAMPLER, /* 0x4 */ + gcSL_CONSTANT, /* 0x5 */ + gcSL_OUTPUT, /* 0x6 */ + gcSL_PHYSICAL, /* 0x7 */ +} +gcSL_TYPE; + +/* Swizzle generator macro. */ +#define gcmSWIZZLE(Component1, Component2, Component3, Component4) \ +( \ + (gcSL_SWIZZLE_ ## Component1 << 0) | \ + (gcSL_SWIZZLE_ ## Component2 << 2) | \ + (gcSL_SWIZZLE_ ## Component3 << 4) | \ + (gcSL_SWIZZLE_ ## Component4 << 6) \ +) + +#define gcmExtractSwizzle(Swizzle, Index) \ + ((gcSL_SWIZZLE) ((((Swizzle) >> (Index * 2)) & 0x3))) + +#define gcmComposeSwizzle(SwizzleX, SwizzleY, SwizzleZ, SwizzleW) \ +( \ + ((SwizzleX) << 0) | \ + ((SwizzleY) << 2) | \ + ((SwizzleZ) << 4) | \ + ((SwizzleW) << 6) \ +) + +/* Possible swizzle values. */ +typedef enum _gcSL_SWIZZLE +{ + gcSL_SWIZZLE_X, /* 0x0 */ + gcSL_SWIZZLE_Y, /* 0x1 */ + gcSL_SWIZZLE_Z, /* 0x2 */ + gcSL_SWIZZLE_W, /* 0x3 */ + /* Combinations. */ + gcSL_SWIZZLE_XXXX = gcmSWIZZLE(X, X, X, X), + gcSL_SWIZZLE_YYYY = gcmSWIZZLE(Y, Y, Y, Y), + gcSL_SWIZZLE_ZZZZ = gcmSWIZZLE(Z, Z, Z, Z), + gcSL_SWIZZLE_WWWW = gcmSWIZZLE(W, W, W, W), + gcSL_SWIZZLE_XYYY = gcmSWIZZLE(X, Y, Y, Y), + gcSL_SWIZZLE_XZZZ = gcmSWIZZLE(X, Z, Z, Z), + gcSL_SWIZZLE_XWWW = gcmSWIZZLE(X, W, W, W), + gcSL_SWIZZLE_YZZZ = gcmSWIZZLE(Y, Z, Z, Z), + gcSL_SWIZZLE_YWWW = gcmSWIZZLE(Y, W, W, W), + gcSL_SWIZZLE_ZWWW = gcmSWIZZLE(Z, W, W, W), + gcSL_SWIZZLE_XYZZ = gcmSWIZZLE(X, Y, Z, Z), + gcSL_SWIZZLE_XYWW = gcmSWIZZLE(X, Y, W, W), + gcSL_SWIZZLE_XZWW = gcmSWIZZLE(X, Z, W, W), + gcSL_SWIZZLE_YZWW = gcmSWIZZLE(Y, Z, W, W), + gcSL_SWIZZLE_XXYZ = gcmSWIZZLE(X, X, Y, Z), + gcSL_SWIZZLE_XYZW = gcmSWIZZLE(X, Y, Z, W), + gcSL_SWIZZLE_XYXY = gcmSWIZZLE(X, Y, X, Y), + gcSL_SWIZZLE_YYZZ = gcmSWIZZLE(Y, Y, Z, Z), + gcSL_SWIZZLE_YYWW = gcmSWIZZLE(Y, Y, W, W), + gcSL_SWIZZLE_ZZZW = gcmSWIZZLE(Z, Z, Z, W), + gcSL_SWIZZLE_XZZW = gcmSWIZZLE(X, Z, Z, W), + gcSL_SWIZZLE_YYZW = gcmSWIZZLE(Y, Y, Z, W), + + gcSL_SWIZZLE_INVALID = 0x7FFFFFFF +} +gcSL_SWIZZLE; + +typedef enum _gcSL_COMPONENT +{ + gcSL_COMPONENT_X, /* 0x0 */ + gcSL_COMPONENT_Y, /* 0x1 */ + gcSL_COMPONENT_Z, /* 0x2 */ + gcSL_COMPONENT_W, /* 0x3 */ + gcSL_COMPONENT_COUNT /* 0x4 */ +} gcSL_COMPONENT; + +#define gcmIsComponentEnabled(Enable, Component) (((Enable) & (1 << (Component))) != 0) + +/******************************************************************************\ +|*********************************** SHADERS **********************************| +\******************************************************************************/ + +/* Shader types. */ +typedef enum _gcSHADER_KIND { + gcSHADER_TYPE_UNKNOWN = 0, + gcSHADER_TYPE_VERTEX, + gcSHADER_TYPE_FRAGMENT, + gcSHADER_TYPE_CL, + gcSHADER_TYPE_PRECOMPILED, + gcSHADER_KIND_COUNT +} gcSHADER_KIND; + +typedef enum _gcGL_DRIVER_VERSION { + gcGL_DRIVER_ES11, /* OpenGL ES 1.1 */ + gcGL_DRIVER_ES20, /* OpenGL ES 2.0 */ + gcGL_DRIVER_ES30 /* OpenGL ES 3.0 */ +} gcGL_DRIVER_VERSION; + +#define gcm +/* gcSHADER objects. */ +typedef struct _gcSHADER * gcSHADER; +typedef struct _gcATTRIBUTE * gcATTRIBUTE; +typedef struct _gcUNIFORM * gcUNIFORM; +typedef struct _gcOUTPUT * gcOUTPUT; +typedef struct _gcsFUNCTION * gcFUNCTION; +typedef struct _gcsKERNEL_FUNCTION * gcKERNEL_FUNCTION; +typedef struct _gcsHINT * gcsHINT_PTR; +typedef struct _gcSHADER_PROFILER * gcSHADER_PROFILER; +typedef struct _gcVARIABLE * gcVARIABLE; + +struct _gcsHINT +{ + /* Numbr of data transfers for Vertex Shader output. */ + gctUINT32 vsOutputCount; + + /* Flag whether the VS has point size or not. */ + gctBOOL vsHasPointSize; + + /* Element count. */ + gctUINT32 elementCount; + + /* Component count. */ + gctUINT32 componentCount; + + /* Number of data transfers for Fragment Shader input. */ + gctUINT32 fsInputCount; + + /* Maximum number of temporary registers used in FS. */ + gctUINT32 fsMaxTemp; + + /* Maximum number of temporary registers used in VS. */ + gctUINT32 vsMaxTemp; + + /* Balance minimum. */ + gctUINT32 balanceMin; + + /* Balance maximum. */ + gctUINT32 balanceMax; + + /* Flag whether the PS outputs the depth value or not. */ + gctBOOL psHasFragDepthOut; + + /* Flag whether the ThreadWalker is in PS. */ + gctBOOL threadWalkerInPS; + +}; + +/* gcSHADER_TYPE enumeration. */ +typedef enum _gcSHADER_TYPE +{ + gcSHADER_FLOAT_X1, /* 0x00 */ + gcSHADER_FLOAT_X2, /* 0x01 */ + gcSHADER_FLOAT_X3, /* 0x02 */ + gcSHADER_FLOAT_X4, /* 0x03 */ + gcSHADER_FLOAT_2X2, /* 0x04 */ + gcSHADER_FLOAT_3X3, /* 0x05 */ + gcSHADER_FLOAT_4X4, /* 0x06 */ + gcSHADER_BOOLEAN_X1, /* 0x07 */ + gcSHADER_BOOLEAN_X2, /* 0x08 */ + gcSHADER_BOOLEAN_X3, /* 0x09 */ + gcSHADER_BOOLEAN_X4, /* 0x0A */ + gcSHADER_INTEGER_X1, /* 0x0B */ + gcSHADER_INTEGER_X2, /* 0x0C */ + gcSHADER_INTEGER_X3, /* 0x0D */ + gcSHADER_INTEGER_X4, /* 0x0E */ + gcSHADER_SAMPLER_1D, /* 0x0F */ + gcSHADER_SAMPLER_2D, /* 0x10 */ + gcSHADER_SAMPLER_3D, /* 0x11 */ + gcSHADER_SAMPLER_CUBIC, /* 0x12 */ + gcSHADER_FIXED_X1, /* 0x13 */ + gcSHADER_FIXED_X2, /* 0x14 */ + gcSHADER_FIXED_X3, /* 0x15 */ + gcSHADER_FIXED_X4, /* 0x16 */ + gcSHADER_IMAGE_2D, /* 0x17 */ /* For OCL. */ + gcSHADER_IMAGE_3D, /* 0x18 */ /* For OCL. */ + gcSHADER_SAMPLER, /* 0x19 */ /* For OCL. */ + gcSHADER_FLOAT_2X3, /* 0x1A */ + gcSHADER_FLOAT_2X4, /* 0x1B */ + gcSHADER_FLOAT_3X2, /* 0x1C */ + gcSHADER_FLOAT_3X4, /* 0x1D */ + gcSHADER_FLOAT_4X2, /* 0x1E */ + gcSHADER_FLOAT_4X3, /* 0x1F */ + gcSHADER_ISAMPLER_2D, /* 0x20 */ + gcSHADER_ISAMPLER_3D, /* 0x21 */ + gcSHADER_ISAMPLER_CUBIC, /* 0x22 */ + gcSHADER_USAMPLER_2D, /* 0x23 */ + gcSHADER_USAMPLER_3D, /* 0x24 */ + gcSHADER_USAMPLER_CUBIC, /* 0x25 */ + gcSHADER_SAMPLER_EXTERNAL_OES, /* 0x26 */ + gcSHADER_TYPE_COUNT +} +gcSHADER_TYPE; + +typedef enum _gcSHADER_VAR_CATEGORY +{ + gcSHADER_VAR_CATEGORY_NORMAL = 0, /* primitive type and its array */ + gcSHADER_VAR_CATEGORY_STRUCT = 1 /* structure */ +} +gcSHADER_VAR_CATEGORY; + +#if GC_ENABLE_LOADTIME_OPT + +typedef struct _gcSHADER_TYPE_INFO +{ + gcSHADER_TYPE type; /* eg. gcSHADER_FLOAT_2X3 is the type */ + gctCONST_STRING name; /* the name of the type: "gcSHADER_FLOAT_2X3" */ + gcSHADER_TYPE baseType; /* its base type is gcSHADER_FLOAT_2 */ + gctINT components; /* it has 2 components */ + gctINT rows; /* and 3 rows */ + gctINT size; /* the size in byte */ +} gcSHADER_TYPE_INFO; + +enum gceLTCDumpOption { + gceLTC_DUMP_UNIFORM = 0x0001, + gceLTC_DUMP_EVALUATION = 0x0002, + gceLTC_DUMP_EXPESSION = 0x0004, + gceLTC_DUMP_COLLECTING = 0x0008, +}; + +gctBOOL gcDumpOption(gctINT Opt); + +extern gcSHADER_TYPE_INFO shader_type_info[]; + +#endif /* GC_ENABLE_LOADTIME_OPT */ + + +#define IS_MATRIX_TYPE(type) \ + (((type >= gcSHADER_FLOAT_2X2) && (type <= gcSHADER_FLOAT_4X4)) || \ + ((type >= gcSHADER_FLOAT_2X3) && (type <= gcSHADER_FLOAT_4X3))) + +/* gcSHADER_PRECISION enumeration. */ +typedef enum _gcSHADER_PRECISION +{ + gcSHADER_PRECISION_DEFAULT, /* 0x00 */ + gcSHADER_PRECISION_HIGH, /* 0x01 */ + gcSHADER_PRECISION_MEDIUM, /* 0x02 */ + gcSHADER_PRECISION_LOW, /* 0x03 */ +} +gcSHADER_PRECISION; + +/* Shader flags. */ +typedef enum _gceSHADER_FLAGS +{ + gcvSHADER_NO_OPTIMIZATION = 0x00, + gcvSHADER_DEAD_CODE = 0x01, + gcvSHADER_RESOURCE_USAGE = 0x02, + gcvSHADER_OPTIMIZER = 0x04, + gcvSHADER_USE_GL_Z = 0x08, + /* + The GC family of GPU cores model GC860 and under require the Z + to be from 0 <= z <= w. + However, OpenGL specifies the Z to be from -w <= z <= w. So we + have to a conversion here: + + z = (z + w) / 2. + + So here we append two instructions to the vertex shader. + */ + gcvSHADER_USE_GL_POSITION = 0x10, + gcvSHADER_USE_GL_FACE = 0x20, + gcvSHADER_USE_GL_POINT_COORD = 0x40, + gcvSHADER_LOADTIME_OPTIMIZER = 0x80, +} +gceSHADER_FLAGS; + +/* Function argument qualifier */ +typedef enum _gceINPUT_OUTPUT +{ + gcvFUNCTION_INPUT, + gcvFUNCTION_OUTPUT, + gcvFUNCTION_INOUT +} +gceINPUT_OUTPUT; + +/* Kernel function property flags. */ +typedef enum _gcePROPERTY_FLAGS +{ + gcvPROPERTY_REQD_WORK_GRP_SIZE = 0x01 +} +gceKERNEL_FUNCTION_PROPERTY_FLAGS; + +/* Uniform flags. */ +typedef enum _gceUNIFORM_FLAGS +{ + gcvUNIFORM_KERNEL_ARG = 0x01, + gcvUNIFORM_KERNEL_ARG_LOCAL = 0x02, + gcvUNIFORM_KERNEL_ARG_SAMPLER = 0x04, + gcvUNIFORM_LOCAL_ADDRESS_SPACE = 0x08, + gcvUNIFORM_PRIVATE_ADDRESS_SPACE = 0x10, + gcvUNIFORM_CONSTANT_ADDRESS_SPACE = 0x20, + gcvUNIFORM_GLOBAL_SIZE = 0x40, + gcvUNIFORM_LOCAL_SIZE = 0x80, + gcvUNIFORM_NUM_GROUPS = 0x100, + gcvUNIFORM_GLOBAL_OFFSET = 0x200, + gcvUNIFORM_WORK_DIM = 0x400, + gcvUNIFORM_KERNEL_ARG_CONSTANT = 0x800, + gcvUNIFORM_KERNEL_ARG_LOCAL_MEM_SIZE = 0x1000, + gcvUNIFORM_KERNEL_ARG_PRIVATE = 0x2000, + gcvUNIFORM_LOADTIME_CONSTANT = 0x4000, +} +gceUNIFORM_FLAGS; + +#define gcdUNIFORM_KERNEL_ARG_MASK (gcvUNIFORM_KERNEL_ARG | \ + gcvUNIFORM_KERNEL_ARG_LOCAL | \ + gcvUNIFORM_KERNEL_ARG_SAMPLER | \ + gcvUNIFORM_KERNEL_ARG_PRIVATE | \ + gcvUNIFORM_KERNEL_ARG_CONSTANT) + +typedef enum _gceVARIABLE_UPDATE_FLAGS +{ + gceVARIABLE_UPDATE_NOUPDATE = 0, + gceVARIABLE_UPDATE_TEMPREG, +}gceVARIABLE_UPDATE_FLAGS; + +/******************************************************************************* +** gcSHADER_SetCompilerVersion +** +** Set the compiler version of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to gcSHADER object +** +** gctINT *Version +** Pointer to a two word version +*/ +gceSTATUS +gcSHADER_SetCompilerVersion( + IN gcSHADER Shader, + IN gctUINT32 *Version + ); + +/******************************************************************************* +** gcSHADER_GetCompilerVersion +** +** Get the compiler version of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctUINT32_PTR *CompilerVersion. +** Pointer to holder of returned compilerVersion pointer +*/ +gceSTATUS +gcSHADER_GetCompilerVersion( + IN gcSHADER Shader, + OUT gctUINT32_PTR *CompilerVersion + ); + +/******************************************************************************* +** gcSHADER_GetType +** +** Get the gcSHADER object's type. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctINT *Type. +** Pointer to return shader type. +*/ +gceSTATUS +gcSHADER_GetType( + IN gcSHADER Shader, + OUT gctINT *Type + ); +/******************************************************************************* +** gcSHADER_Construct +******************************************************************************** +** +** Construct a new gcSHADER object. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Type of gcSHADER object to cerate. 'ShaderType' can be one of the +** following: +** +** gcSHADER_TYPE_VERTEX Vertex shader. +** gcSHADER_TYPE_FRAGMENT Fragment shader. +** +** OUTPUT: +** +** gcSHADER * Shader +** Pointer to a variable receiving the gcSHADER object pointer. +*/ +gceSTATUS +gcSHADER_Construct( + IN gcoHAL Hal, + IN gctINT ShaderType, + OUT gcSHADER * Shader + ); + +/******************************************************************************* +** gcSHADER_Destroy +******************************************************************************** +** +** Destroy a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Destroy( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_Copy +******************************************************************************** +** +** Copy a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSHADER Source +** Pointer to a gcSHADER object that will be copied. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Copy( + IN gcSHADER Shader, + IN gcSHADER Source + ); + +/******************************************************************************* +** gcSHADER_LoadHeader +** +** Load a gcSHADER object from a binary buffer. The binary buffer is layed out +** as follows: +** // Six word header +** // Signature, must be 'S','H','D','R'. +** gctINT8 signature[4]; +** gctUINT32 binFileVersion; +** gctUINT32 compilerVersion[2]; +** gctUINT32 gcSLVersion; +** gctUINT32 binarySize; +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** Shader type will be returned if type in shader object is not gcSHADER_TYPE_PRECOMPILED +** +** gctPOINTER Buffer +** Pointer to a binary buffer containing the shader data to load. +** +** gctSIZE_T BufferSize +** Number of bytes inside the binary buffer pointed to by 'Buffer'. +** +** OUTPUT: +** nothing +** +*/ +gceSTATUS +gcSHADER_LoadHeader( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN gctSIZE_T BufferSize, + OUT gctUINT32 * ShaderVersion + ); + +/******************************************************************************* +** gcSHADER_LoadKernel +** +** Load a kernel function given by name into gcSHADER object +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSTRING KernelName +** Pointer to a kernel function name +** +** OUTPUT: +** nothing +** +*/ +gceSTATUS +gcSHADER_LoadKernel( + IN gcSHADER Shader, + IN gctSTRING KernelName + ); + +/******************************************************************************* +** gcSHADER_Load +******************************************************************************** +** +** Load a gcSHADER object from a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer containg the shader data to load. +** +** gctSIZE_T BufferSize +** Number of bytes inside the binary buffer pointed to by 'Buffer'. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Load( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN gctSIZE_T BufferSize + ); + +/******************************************************************************* +** gcSHADER_Save +******************************************************************************** +** +** Save a gcSHADER object to a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer to be used as storage for the gcSHADER +** object. If 'Buffer' is gcvNULL, the gcSHADER object will not be saved, +** but the number of bytes required to hold the binary output for the +** gcSHADER object will be returned. +** +** gctSIZE_T * BufferSize +** Pointer to a variable holding the number of bytes allocated in +** 'Buffer'. Only valid if 'Buffer' is not gcvNULL. +** +** OUTPUT: +** +** gctSIZE_T * BufferSize +** Pointer to a variable receiving the number of bytes required to hold +** the binary form of the gcSHADER object. +*/ +gceSTATUS +gcSHADER_Save( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN OUT gctSIZE_T * BufferSize + ); + +/******************************************************************************* +** gcSHADER_LoadEx +******************************************************************************** +** +** Load a gcSHADER object from a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer containg the shader data to load. +** +** gctSIZE_T BufferSize +** Number of bytes inside the binary buffer pointed to by 'Buffer'. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_LoadEx( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN gctSIZE_T BufferSize + ); + +/******************************************************************************* +** gcSHADER_SaveEx +******************************************************************************** +** +** Save a gcSHADER object to a binary buffer. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctPOINTER Buffer +** Pointer to a binary buffer to be used as storage for the gcSHADER +** object. If 'Buffer' is gcvNULL, the gcSHADER object will not be saved, +** but the number of bytes required to hold the binary output for the +** gcSHADER object will be returned. +** +** gctSIZE_T * BufferSize +** Pointer to a variable holding the number of bytes allocated in +** 'Buffer'. Only valid if 'Buffer' is not gcvNULL. +** +** OUTPUT: +** +** gctSIZE_T * BufferSize +** Pointer to a variable receiving the number of bytes required to hold +** the binary form of the gcSHADER object. +*/ +gceSTATUS +gcSHADER_SaveEx( + IN gcSHADER Shader, + IN gctPOINTER Buffer, + IN OUT gctSIZE_T * BufferSize + ); + +/******************************************************************************* +** gcSHADER_ReallocateAttributes +** +** Reallocate an array of pointers to gcATTRIBUTE objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateAttributes( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddAttribute +******************************************************************************** +** +** Add an attribute to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the attribute to add. +** +** gcSHADER_TYPE Type +** Type of the attribute to add. +** +** gctSIZE_T Length +** Array length of the attribute to add. 'Length' must be at least 1. +** +** gctBOOL IsTexture +** gcvTRUE if the attribute is used as a texture coordinate, gcvFALSE if not. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_AddAttribute( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctBOOL IsTexture, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_GetAttributeCount +******************************************************************************** +** +** Get the number of attributes for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of attributes. +*/ +gceSTATUS +gcSHADER_GetAttributeCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetAttribute +******************************************************************************** +** +** Get the gcATTRIBUTE object poniter for an indexed attribute for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the attribute to retrieve. +** +** OUTPUT: +** +** gcATTRIBUTE * Attribute +** Pointer to a variable receiving the gcATTRIBUTE object pointer. +*/ +gceSTATUS +gcSHADER_GetAttribute( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcATTRIBUTE * Attribute + ); + +/******************************************************************************* +** gcSHADER_ReallocateUniforms +** +** Reallocate an array of pointers to gcUNIFORM objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateUniforms( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddUniform +******************************************************************************** +** +** Add an uniform to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the uniform to add. +** +** gcSHADER_TYPE Type +** Type of the uniform to add. +** +** gctSIZE_T Length +** Array length of the uniform to add. 'Length' must be at least 1. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_AddUniform( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + OUT gcUNIFORM * Uniform + ); + + +/******************************************************************************* +** gcSHADER_AddUniformEx +******************************************************************************** +** +** Add an uniform to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the uniform to add. +** +** gcSHADER_TYPE Type +** Type of the uniform to add. +** +** gcSHADER_PRECISION precision +** Precision of the uniform to add. +** +** gctSIZE_T Length +** Array length of the uniform to add. 'Length' must be at least 1. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_AddUniformEx( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gcSHADER_PRECISION precision, + IN gctSIZE_T Length, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_GetUniformCount +******************************************************************************** +** +** Get the number of uniforms for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of uniforms. +*/ +gceSTATUS +gcSHADER_GetUniformCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetUniform +******************************************************************************** +** +** Get the gcUNIFORM object pointer for an indexed uniform for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of the uniform to retrieve. +** +** OUTPUT: +** +** gcUNIFORM * Uniform +** Pointer to a variable receiving the gcUNIFORM object pointer. +*/ +gceSTATUS +gcSHADER_GetUniform( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcUNIFORM * Uniform + ); + +/******************************************************************************* +** gcSHADER_GetKernelFucntion +** +** Get the gcKERNEL_FUNCTION object pointer for an indexed kernel function for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of kernel function to retreive the name for. +** +** OUTPUT: +** +** gcKERNEL_FUNCTION * KernelFunction +** Pointer to a variable receiving the gcKERNEL_FUNCTION object pointer. +*/ +gceSTATUS +gcSHADER_GetKernelFunction( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcKERNEL_FUNCTION * KernelFunction + ); + +gceSTATUS +gcSHADER_GetKernelFunctionByName( + IN gcSHADER Shader, + IN gctSTRING KernelName, + OUT gcKERNEL_FUNCTION * KernelFunction + ); +/******************************************************************************* +** gcSHADER_GetKernelFunctionCount +** +** Get the number of kernel functions for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of kernel functions. +*/ +gceSTATUS +gcSHADER_GetKernelFunctionCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_ReallocateOutputs +** +** Reallocate an array of pointers to gcOUTPUT objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateOutputs( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddOutput +******************************************************************************** +** +** Add an output to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the output to add. +** +** gcSHADER_TYPE Type +** Type of the output to add. +** +** gctSIZE_T Length +** Array length of the output to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the output value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOutput( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + +gceSTATUS +gcSHADER_AddOutputIndexed( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gctSIZE_T Index, + IN gctUINT16 TempIndex + ); + +/******************************************************************************* +** gcSHADER_GetOutputCount +******************************************************************************** +** +** Get the number of outputs for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of outputs. +*/ +gceSTATUS +gcSHADER_GetOutputCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetOutput +******************************************************************************** +** +** Get the gcOUTPUT object pointer for an indexed output for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of output to retrieve. +** +** OUTPUT: +** +** gcOUTPUT * Output +** Pointer to a variable receiving the gcOUTPUT object pointer. +*/ +gceSTATUS +gcSHADER_GetOutput( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcOUTPUT * Output + ); + + +/******************************************************************************* +** gcSHADER_GetOutputByName +******************************************************************************** +** +** Get the gcOUTPUT object pointer for this shader by output name. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSTRING name +** Name of output to retrieve. +** +** gctSIZE_T nameLength +** Length of name to retrieve +** +** OUTPUT: +** +** gcOUTPUT * Output +** Pointer to a variable receiving the gcOUTPUT object pointer. +*/ +gceSTATUS +gcSHADER_GetOutputByName( + IN gcSHADER Shader, + IN gctSTRING name, + IN gctSIZE_T nameLength, + OUT gcOUTPUT * Output + ); + +/******************************************************************************* +** gcSHADER_ReallocateVariables +** +** Reallocate an array of pointers to gcVARIABLE objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateVariables( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +/******************************************************************************* +** gcSHADER_AddVariable +******************************************************************************** +** +** Add a variable to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the variable to add. +** +** gcSHADER_TYPE Type +** Type of the variable to add. +** +** gctSIZE_T Length +** Array length of the variable to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the variable value. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddVariable( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister + ); + + +/******************************************************************************* +** gcSHADER_AddVariableEx +******************************************************************************** +** +** Add a variable to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctCONST_STRING Name +** Name of the variable to add. +** +** gcSHADER_TYPE Type +** Type of the variable to add. +** +** gctSIZE_T Length +** Array length of the variable to add. 'Length' must be at least 1. +** +** gctUINT16 TempRegister +** Temporary register index that holds the variable value. +** +** gcSHADER_VAR_CATEGORY varCategory +** Variable category, normal or struct. +** +** gctUINT16 numStructureElement +** If struct, its element number. +** +** gctINT16 parent +** If struct, parent index in gcSHADER.variables. +** +** gctINT16 preSibling +** If struct, previous sibling index in gcSHADER.variables. +** +** gctINT16* ThisVarIndex +** Returned value about variable index in gcSHADER. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddVariableEx( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + IN gctUINT16 TempRegister, + IN gcSHADER_VAR_CATEGORY varCategory, + IN gctUINT16 numStructureElement, + IN gctINT16 parent, + IN gctINT16 preSibling, + OUT gctINT16* ThisVarIndex + ); + +/******************************************************************************* +** gcSHADER_UpdateVariable +******************************************************************************** +** +** Update a variable to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of variable to retrieve. +** +** gceVARIABLE_UPDATE_FLAGS flag +** Flag which property of variable will be updated. +** +** gctUINT16 newValue +** New value to update. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_UpdateVariable( + IN gcSHADER Shader, + IN gctUINT Index, + IN gceVARIABLE_UPDATE_FLAGS flag, + IN gctUINT16 newValue + ); + +/******************************************************************************* +** gcSHADER_GetVariableCount +******************************************************************************** +** +** Get the number of variables for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * Count +** Pointer to a variable receiving the number of variables. +*/ +gceSTATUS +gcSHADER_GetVariableCount( + IN gcSHADER Shader, + OUT gctSIZE_T * Count + ); + +/******************************************************************************* +** gcSHADER_GetVariable +******************************************************************************** +** +** Get the gcVARIABLE object pointer for an indexed variable for this shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Index +** Index of variable to retrieve. +** +** OUTPUT: +** +** gcVARIABLE * Variable +** Pointer to a variable receiving the gcVARIABLE object pointer. +*/ +gceSTATUS +gcSHADER_GetVariable( + IN gcSHADER Shader, + IN gctUINT Index, + OUT gcVARIABLE * Variable + ); + +/******************************************************************************* +** gcSHADER_AddOpcode +******************************************************************************** +** +** Add an opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the target +** of the opcode. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcode( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddOpcode2( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeIndexed +******************************************************************************** +** +** Add an opcode to a gcSHADER object that writes to an dynamically indexed +** target. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the +** target of the opcode. +** +** gcSL_INDEXED Mode +** Location of the dynamic index inside the temporary register. Valid +** values can be: +** +** gcSL_INDEXED_X - Use x component of the temporary register. +** gcSL_INDEXED_Y - Use y component of the temporary register. +** gcSL_INDEXED_Z - Use z component of the temporary register. +** gcSL_INDEXED_W - Use w component of the temporary register. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the temporary register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeIndexed( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditionIndexed +** +** Add an opcode to a gcSHADER object that writes to an dynamically indexed +** target. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition to check. +** +** gctUINT16 TempRegister +** Temporary register index that acts as the target of the opcode. +** +** gctUINT8 Enable +** Write enable bits for the temporary register that acts as the +** target of the opcode. +** +** gcSL_INDEXED Indexed +** Location of the dynamic index inside the temporary register. Valid +** values can be: +** +** gcSL_INDEXED_X - Use x component of the temporary register. +** gcSL_INDEXED_Y - Use y component of the temporary register. +** gcSL_INDEXED_Z - Use z component of the temporary register. +** gcSL_INDEXED_W - Use w component of the temporary register. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditionIndexed( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT16 TempRegister, + IN gctUINT8 Enable, + IN gcSL_INDEXED Indexed, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditional +******************************************************************************** +** +** Add an conditional opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition that needs to evaluate to gcvTRUE in order for the opcode to +** execute. +** +** gctUINT Label +** Target label if 'Condition' evaluates to gcvTRUE. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditional( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditionalFormatted +** +** Add an conditional jump or call opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition that needs to evaluate to gcvTRUE in order for the opcode to +** execute. +** +** gcSL_FORMAT Format +** Format of conditional operands +** +** gctUINT Label +** Target label if 'Condition' evaluates to gcvTRUE. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditionalFormatted( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gcSL_FORMAT Format, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddOpcodeConditionalFormattedEnable +** +** Add an conditional jump or call opcode to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_OPCODE Opcode +** Opcode to add. +** +** gcSL_CONDITION Condition +** Condition that needs to evaluate to gcvTRUE in order for the opcode to +** execute. +** +** gcSL_FORMAT Format +** Format of conditional operands +** +** gctUINT8 Enable +** Write enable value for the target of the opcode. +** +** gctUINT Label +** Target label if 'Condition' evaluates to gcvTRUE. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddOpcodeConditionalFormattedEnable( + IN gcSHADER Shader, + IN gcSL_OPCODE Opcode, + IN gcSL_CONDITION Condition, + IN gcSL_FORMAT Format, + IN gctUINT8 Enable, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddLabel +******************************************************************************** +** +** Define a label at the current instruction of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT Label +** Label to define. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddLabel( + IN gcSHADER Shader, + IN gctUINT Label + ); + +/******************************************************************************* +** gcSHADER_AddSource +******************************************************************************** +** +** Add a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSource( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceIndexed +******************************************************************************** +** +** Add a dynamically indexed source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcSL_TYPE Type +** Type of the source operand. +** +** gctUINT16 SourceIndex +** Index of the source operand. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gcSL_INDEXED Mode +** Addressing mode for the index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** gcSL_FORMAT Format +** Format of the source operand. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceIndexed( + IN gcSHADER Shader, + IN gcSL_TYPE Type, + IN gctUINT16 SourceIndex, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttribute +******************************************************************************** +** +** Add an attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttribute( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceAttributeIndexed +******************************************************************************** +** +** Add an indexed attribute as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the attribute in case the attribute is a matrix +** or array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceAttributeIndexed( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniform +******************************************************************************** +** +** Add a uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniform( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index + ); + +/******************************************************************************* +** gcSHADER_AddSourceUniformIndexed +******************************************************************************** +** +** Add an indexed uniform as a source operand to a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctUINT8 Swizzle +** x, y, z, and w swizzle values packed into one 8-bit value. +** +** gctINT Index +** Static index into the uniform in case the uniform is a matrix or +** array. +** +** gcSL_INDEXED Mode +** Addressing mode of the dynamic index. +** +** gctUINT16 IndexRegister +** Temporary register index that holds the dynamic index. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceUniformIndexed( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +gceSTATUS +gcSHADER_AddSourceSamplerIndexed( + IN gcSHADER Shader, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister + ); + +gceSTATUS +gcSHADER_AddSourceAttributeFormatted( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddSourceAttributeIndexedFormatted( + IN gcSHADER Shader, + IN gcATTRIBUTE Attribute, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddSourceUniformFormatted( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddSourceUniformIndexedFormatted( + IN gcSHADER Shader, + IN gcUNIFORM Uniform, + IN gctUINT8 Swizzle, + IN gctINT Index, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +gceSTATUS +gcSHADER_AddSourceSamplerIndexedFormatted( + IN gcSHADER Shader, + IN gctUINT8 Swizzle, + IN gcSL_INDEXED Mode, + IN gctUINT16 IndexRegister, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_AddSourceConstant +******************************************************************************** +** +** Add a constant floating point value as a source operand to a gcSHADER +** object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctFLOAT Constant +** Floating point constant. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceConstant( + IN gcSHADER Shader, + IN gctFLOAT Constant + ); + +/******************************************************************************* +** gcSHADER_AddSourceConstantFormatted +******************************************************************************** +** +** Add a constant value as a source operand to a gcSHADER +** object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** void * Constant +** Pointer to constant. +** +** gcSL_FORMAT Format +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_AddSourceConstantFormatted( + IN gcSHADER Shader, + IN void *Constant, + IN gcSL_FORMAT Format + ); + +/******************************************************************************* +** gcSHADER_Pack +******************************************************************************** +** +** Pack a dynamically created gcSHADER object by trimming the allocated arrays +** and resolving all the labeling. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_Pack( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcSHADER_SetOptimizationOption +******************************************************************************** +** +** Set optimization option of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctUINT OptimizationOption +** Optimization option. Can be one of the following: +** +** 0 - No optimization. +** 1 - Full optimization. +** Other value - For optimizer testing. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcSHADER_SetOptimizationOption( + IN gcSHADER Shader, + IN gctUINT OptimizationOption + ); + +/******************************************************************************* +** gcSHADER_ReallocateFunctions +** +** Reallocate an array of pointers to gcFUNCTION objects. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcSHADER_ReallocateFunctions( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +gceSTATUS +gcSHADER_AddFunction( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + OUT gcFUNCTION * Function + ); + +gceSTATUS +gcSHADER_ReallocateKernelFunctions( + IN gcSHADER Shader, + IN gctSIZE_T Count + ); + +gceSTATUS +gcSHADER_AddKernelFunction( + IN gcSHADER Shader, + IN gctCONST_STRING Name, + OUT gcKERNEL_FUNCTION * KernelFunction + ); + +gceSTATUS +gcSHADER_BeginFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +gceSTATUS +gcSHADER_EndFunction( + IN gcSHADER Shader, + IN gcFUNCTION Function + ); + +gceSTATUS +gcSHADER_BeginKernelFunction( + IN gcSHADER Shader, + IN gcKERNEL_FUNCTION KernelFunction + ); + +gceSTATUS +gcSHADER_EndKernelFunction( + IN gcSHADER Shader, + IN gcKERNEL_FUNCTION KernelFunction, + IN gctSIZE_T LocalMemorySize + ); + +gceSTATUS +gcSHADER_SetMaxKernelFunctionArgs( + IN gcSHADER Shader, + IN gctUINT32 MaxKernelFunctionArgs + ); + +/******************************************************************************* +** gcSHADER_SetConstantMemorySize +** +** Set the constant memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T ConstantMemorySize +** Constant memory size in bytes +** +** gctCHAR *ConstantMemoryBuffer +** Constant memory buffer +*/ +gceSTATUS +gcSHADER_SetConstantMemorySize( + IN gcSHADER Shader, + IN gctSIZE_T ConstantMemorySize, + IN gctCHAR * ConstantMemoryBuffer + ); + +/******************************************************************************* +** gcSHADER_GetConstantMemorySize +** +** Set the constant memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * ConstantMemorySize +** Pointer to a variable receiving constant memory size in bytes +** +** gctCHAR **ConstantMemoryBuffer. +** Pointer to a variable for returned shader constant memory buffer. +*/ +gceSTATUS +gcSHADER_GetConstantMemorySize( + IN gcSHADER Shader, + OUT gctSIZE_T * ConstantMemorySize, + OUT gctCHAR ** ConstantMemoryBuffer + ); + +/******************************************************************************* +** gcSHADER_SetPrivateMemorySize +** +** Set the private memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T PrivateMemorySize +** Private memory size in bytes +*/ +gceSTATUS +gcSHADER_SetPrivateMemorySize( + IN gcSHADER Shader, + IN gctSIZE_T PrivateMemorySize + ); + +/******************************************************************************* +** gcSHADER_GetPrivateMemorySize +** +** Set the private memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * PrivateMemorySize +** Pointer to a variable receiving private memory size in bytes +*/ +gceSTATUS +gcSHADER_GetPrivateMemorySize( + IN gcSHADER Shader, + OUT gctSIZE_T * PrivateMemorySize + ); + +/******************************************************************************* +** gcSHADER_SetLocalMemorySize +** +** Set the local memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** gctSIZE_T LocalMemorySize +** Local memory size in bytes +*/ +gceSTATUS +gcSHADER_SetLocalMemorySize( + IN gcSHADER Shader, + IN gctSIZE_T LocalMemorySize + ); + +/******************************************************************************* +** gcSHADER_GetLocalMemorySize +** +** Set the local memory address space size of a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +** OUTPUT: +** +** gctSIZE_T * LocalMemorySize +** Pointer to a variable receiving lcoal memory size in bytes +*/ +gceSTATUS +gcSHADER_GetLocalMemorySize( + IN gcSHADER Shader, + OUT gctSIZE_T * LocalMemorySize + ); + + +/******************************************************************************* +** gcSHADER_CheckValidity +** +** Check validity for a gcSHADER object. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object. +** +*/ +gceSTATUS +gcSHADER_CheckValidity( + IN gcSHADER Shader + ); + +/******************************************************************************* +** gcATTRIBUTE_GetType +******************************************************************************** +** +** Get the type and array length of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the attribute. 'Type' +** can be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** attribute was declared as an array. If the attribute was not +** declared as an array, the array length will be 1. 'ArrayLength' can +** be gcvNULL, in which case no array length will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetType( + IN gcATTRIBUTE Attribute, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcATTRIBUTE_GetName +******************************************************************************** +** +** Get the name of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the attribute name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the attribute name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcATTRIBUTE_GetName( + IN gcATTRIBUTE Attribute, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcATTRIBUTE_IsEnabled +******************************************************************************** +** +** Query the enabled state of a gcATTRIBUTE object. +** +** INPUT: +** +** gcATTRIBUTE Attribute +** Pointer to a gcATTRIBUTE object. +** +** OUTPUT: +** +** gctBOOL * Enabled +** Pointer to a variable receiving the enabled state of the attribute. +*/ +gceSTATUS +gcATTRIBUTE_IsEnabled( + IN gcATTRIBUTE Attribute, + OUT gctBOOL * Enabled + ); + +/******************************************************************************* +** gcUNIFORM_GetType +******************************************************************************** +** +** Get the type and array length of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the uniform. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** uniform was declared as an array. If the uniform was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcUNIFORM_GetType( + IN gcUNIFORM Uniform, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcUNIFORM_GetTypeEx +******************************************************************************** +** +** Get the type and array length of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the uniform. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gcSHADER_PRECISION * Precision +** Pointer to a variable receiving the precision of the uniform. 'Precision' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** uniform was declared as an array. If the uniform was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcUNIFORM_GetTypeEx( + IN gcUNIFORM Uniform, + OUT gcSHADER_TYPE * Type, + OUT gcSHADER_PRECISION * Precision, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcUNIFORM_GetFlags +******************************************************************************** +** +** Get the flags of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gceUNIFORM_FLAGS * Flags +** Pointer to a variable receiving the flags of the uniform. +** +*/ +gceSTATUS +gcUNIFORM_GetFlags( + IN gcUNIFORM Uniform, + OUT gceUNIFORM_FLAGS * Flags + ); + +/******************************************************************************* +** gcUNIFORM_SetFlags +******************************************************************************** +** +** Set the flags of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gceUNIFORM_FLAGS Flags +** Flags of the uniform to be set. +** +** OUTPUT: +** Nothing. +** +*/ +gceSTATUS +gcUNIFORM_SetFlags( + IN gcUNIFORM Uniform, + IN gceUNIFORM_FLAGS Flags + ); + +/******************************************************************************* +** gcUNIFORM_GetName +******************************************************************************** +** +** Get the name of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the uniform name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the uniform name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcUNIFORM_GetName( + IN gcUNIFORM Uniform, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +** gcUNIFORM_GetSampler +******************************************************************************** +** +** Get the physical sampler number for a sampler gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gctUINT32 * Sampler +** Pointer to a variable receiving the physical sampler. +*/ +gceSTATUS +gcUNIFORM_GetSampler( + IN gcUNIFORM Uniform, + OUT gctUINT32 * Sampler + ); + +/******************************************************************************* +** gcUNIFORM_GetFormat +** +** Get the type and array length of a gcUNIFORM object. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** OUTPUT: +** +** gcSL_FORMAT * Format +** Pointer to a variable receiving the format of element of the uniform. +** 'Type' can be gcvNULL, in which case no type will be returned. +** +** gctBOOL * IsPointer +** Pointer to a variable receiving the state wheter the uniform is a pointer. +** 'IsPointer' can be gcvNULL, in which case no array length will be returned. +*/ +gceSTATUS +gcUNIFORM_GetFormat( + IN gcUNIFORM Uniform, + OUT gcSL_FORMAT * Format, + OUT gctBOOL * IsPointer + ); + +/******************************************************************************* +** gcUNIFORM_SetFormat +** +** Set the format and isPointer of a uniform. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gcSL_FORMAT Format +** Format of element of the uniform shaderType. +** +** gctBOOL IsPointer +** Wheter the uniform is a pointer. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetFormat( + IN gcUNIFORM Uniform, + IN gcSL_FORMAT Format, + IN gctBOOL IsPointer + ); + +/******************************************************************************* +** gcUNIFORM_SetValue +******************************************************************************** +** +** Set the value of a uniform in integer. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctINT * Value +** Pointer to a buffer holding the integer values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValue( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueX +******************************************************************************** +** +** Set the value of a uniform in fixed point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFIXED_POINT * Value +** Pointer to a buffer holding the fixed point values for the uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueX( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN gctFIXED_POINT * Value + ); + +/******************************************************************************* +** gcUNIFORM_SetValueF +******************************************************************************** +** +** Set the value of a uniform in floating point. +** +** INPUT: +** +** gcUNIFORM Uniform +** Pointer to a gcUNIFORM object. +** +** gctSIZE_T Count +** Number of entries to program if the uniform has been declared as an +** array. +** +** const gctFLOAT * Value +** Pointer to a buffer holding the floating point values for the +** uniform. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gcUNIFORM_SetValueF( + IN gcUNIFORM Uniform, + IN gctSIZE_T Count, + IN const gctFLOAT * Value + ); + +/******************************************************************************* +** gcOUTPUT_GetType +******************************************************************************** +** +** Get the type and array length of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gcSHADER_TYPE * Type +** Pointer to a variable receiving the type of the output. 'Type' can +** be gcvNULL, in which case no type will be returned. +** +** gctSIZE_T * ArrayLength +** Pointer to a variable receiving the length of the array if the +** output was declared as an array. If the output was not declared +** as an array, the array length will be 1. 'ArrayLength' can be gcvNULL, +** in which case no array length will be returned. +*/ +gceSTATUS +gcOUTPUT_GetType( + IN gcOUTPUT Output, + OUT gcSHADER_TYPE * Type, + OUT gctSIZE_T * ArrayLength + ); + +/******************************************************************************* +** gcOUTPUT_GetIndex +******************************************************************************** +** +** Get the index of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctUINT * Index +** Pointer to a variable receiving the temporary register index of the +** output. 'Index' can be gcvNULL,. in which case no index will be +** returned. +*/ +gceSTATUS +gcOUTPUT_GetIndex( + IN gcOUTPUT Output, + OUT gctUINT * Index + ); + +/******************************************************************************* +** gcOUTPUT_GetName +******************************************************************************** +** +** Get the name of a gcOUTPUT object. +** +** INPUT: +** +** gcOUTPUT Output +** Pointer to a gcOUTPUT object. +** +** OUTPUT: +** +** gctSIZE_T * Length +** Pointer to a variable receiving the length of the output name. +** 'Length' can be gcvNULL, in which case no length will be returned. +** +** gctCONST_STRING * Name +** Pointer to a variable receiving the pointer to the output name. +** 'Name' can be gcvNULL, in which case no name will be returned. +*/ +gceSTATUS +gcOUTPUT_GetName( + IN gcOUTPUT Output, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +/******************************************************************************* +*********************************************************** F U N C T I O N S ** +*******************************************************************************/ + +/******************************************************************************* +** gcFUNCTION_ReallocateArguments +** +** Reallocate an array of gcsFUNCTION_ARGUMENT objects. +** +** INPUT: +** +** gcFUNCTION Function +** Pointer to a gcFUNCTION object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcFUNCTION_ReallocateArguments( + IN gcFUNCTION Function, + IN gctSIZE_T Count + ); + +gceSTATUS +gcFUNCTION_AddArgument( + IN gcFUNCTION Function, + IN gctUINT16 TempIndex, + IN gctUINT8 Enable, + IN gctUINT8 Qualifier + ); + +gceSTATUS +gcFUNCTION_GetArgument( + IN gcFUNCTION Function, + IN gctUINT16 Index, + OUT gctUINT16_PTR Temp, + OUT gctUINT8_PTR Enable, + OUT gctUINT8_PTR Swizzle + ); + +gceSTATUS +gcFUNCTION_GetLabel( + IN gcFUNCTION Function, + OUT gctUINT_PTR Label + ); + +/******************************************************************************* +************************* K E R N E L P R O P E R T Y F U N C T I O N S ** +*******************************************************************************/ +/*******************************************************************************/ +gceSTATUS +gcKERNEL_FUNCTION_AddKernelFunctionProperties( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctINT propertyType, + IN gctSIZE_T propertySize, + IN gctINT * values + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetPropertyCount( + IN gcKERNEL_FUNCTION KernelFunction, + OUT gctSIZE_T * Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetProperty( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctUINT Index, + OUT gctSIZE_T * propertySize, + OUT gctINT * propertyType, + OUT gctINT * propertyValues + ); + + +/******************************************************************************* +*******************************I M A G E S A M P L E R F U N C T I O N S ** +*******************************************************************************/ +/******************************************************************************* +** gcKERNEL_FUNCTION_ReallocateImageSamplers +** +** Reallocate an array of pointers to image sampler pair. +** +** INPUT: +** +** gcKERNEL_FUNCTION KernelFunction +** Pointer to a gcKERNEL_FUNCTION object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcKERNEL_FUNCTION_ReallocateImageSamplers( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctSIZE_T Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_AddImageSampler( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctUINT8 ImageNum, + IN gctBOOL IsConstantSamplerType, + IN gctUINT32 SamplerType + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetImageSamplerCount( + IN gcKERNEL_FUNCTION KernelFunction, + OUT gctSIZE_T * Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetImageSampler( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctUINT Index, + OUT gctUINT8 *ImageNum, + OUT gctBOOL *IsConstantSamplerType, + OUT gctUINT32 *SamplerType + ); + +/******************************************************************************* +*********************************************K E R N E L F U N C T I O N S ** +*******************************************************************************/ + +/******************************************************************************* +** gcKERNEL_FUNCTION_ReallocateArguments +** +** Reallocate an array of gcsFUNCTION_ARGUMENT objects. +** +** INPUT: +** +** gcKERNEL_FUNCTION Function +** Pointer to a gcKERNEL_FUNCTION object. +** +** gctSIZE_T Count +** Array count to reallocate. 'Count' must be at least 1. +*/ +gceSTATUS +gcKERNEL_FUNCTION_ReallocateArguments( + IN gcKERNEL_FUNCTION Function, + IN gctSIZE_T Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_AddArgument( + IN gcKERNEL_FUNCTION Function, + IN gctUINT16 TempIndex, + IN gctUINT8 Enable, + IN gctUINT8 Qualifier + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetArgument( + IN gcKERNEL_FUNCTION Function, + IN gctUINT16 Index, + OUT gctUINT16_PTR Temp, + OUT gctUINT8_PTR Enable, + OUT gctUINT8_PTR Swizzle + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetLabel( + IN gcKERNEL_FUNCTION Function, + OUT gctUINT_PTR Label + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetName( + IN gcKERNEL_FUNCTION KernelFunction, + OUT gctSIZE_T * Length, + OUT gctCONST_STRING * Name + ); + +gceSTATUS +gcKERNEL_FUNCTION_ReallocateUniformArguments( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctSIZE_T Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_AddUniformArgument( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctCONST_STRING Name, + IN gcSHADER_TYPE Type, + IN gctSIZE_T Length, + OUT gcUNIFORM * UniformArgument + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetUniformArgumentCount( + IN gcKERNEL_FUNCTION KernelFunction, + OUT gctSIZE_T * Count + ); + +gceSTATUS +gcKERNEL_FUNCTION_GetUniformArgument( + IN gcKERNEL_FUNCTION KernelFunction, + IN gctUINT Index, + OUT gcUNIFORM * UniformArgument + ); + +gceSTATUS +gcKERNEL_FUNCTION_SetCodeEnd( + IN gcKERNEL_FUNCTION KernelFunction + ); + +/******************************************************************************* +** gcCompileShader +******************************************************************************** +** +** Compile a shader. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctINT ShaderType +** Shader type to compile. Can be one of the following values: +** +** gcSHADER_TYPE_VERTEX +** Compile a vertex shader. +** +** gcSHADER_TYPE_FRAGMENT +** Compile a fragment shader. +** +** gctSIZE_T SourceSize +** Size of the source buffer in bytes. +** +** gctCONST_STRING Source +** Pointer to the buffer containing the shader source code. +** +** OUTPUT: +** +** gcSHADER * Binary +** Pointer to a variable receiving the pointer to a gcSHADER object +** containg the compiled shader code. +** +** gctSTRING * Log +** Pointer to a variable receiving a string pointer containging the +** compile log. +*/ +gceSTATUS +gcCompileShader( + IN gcoHAL Hal, + IN gctINT ShaderType, + IN gctSIZE_T SourceSize, + IN gctCONST_STRING Source, + OUT gcSHADER * Binary, + OUT gctSTRING * Log + ); + +/******************************************************************************* +** gcOptimizeShader +******************************************************************************** +** +** Optimize a shader. +** +** INPUT: +** +** gcSHADER Shader +** Pointer to a gcSHADER object holding information about the compiled +** shader. +** +** gctFILE LogFile +** Pointer to an open FILE object. +*/ +gceSTATUS +gcOptimizeShader( + IN gcSHADER Shader, + IN gctFILE LogFile + ); + +/******************************************************************************* +** gcLinkShaders +******************************************************************************** +** +** Link two shaders and generate a harwdare specific state buffer by compiling +** the compiler generated code through the resource allocator and code +** generator. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to a gcSHADER object holding information about the compiled +** vertex shader. +** +** gcSHADER FragmentShader +** Pointer to a gcSHADER object holding information about the compiled +** fragment shader. +** +** gceSHADER_FLAGS Flags +** Compiler flags. Can be any of the following: +** +** gcvSHADER_DEAD_CODE - Dead code elimination. +** gcvSHADER_RESOURCE_USAGE - Resource usage optimizaion. +** gcvSHADER_OPTIMIZER - Full optimization. +** gcvSHADER_USE_GL_Z - Use OpenGL ES Z coordinate. +** gcvSHADER_USE_GL_POSITION - Use OpenGL ES gl_Position. +** gcvSHADER_USE_GL_FACE - Use OpenGL ES gl_FaceForward. +** +** OUTPUT: +** +** gctSIZE_T * StateBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'StateBuffer'. +** +** gctPOINTER * StateBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLinkShaders( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gceSHADER_FLAGS Flags, + OUT gctSIZE_T * StateBufferSize, + OUT gctPOINTER * StateBuffer, + OUT gcsHINT_PTR * Hints + ); + +/******************************************************************************* +** gcLoadShaders +******************************************************************************** +** +** Load a pre-compiled and pre-linked shader program into the hardware. +** +** INPUT: +** +** gcoHAL Hal +** Pointer to a gcoHAL object. +** +** gctSIZE_T StateBufferSize +** The number of bytes in the 'StateBuffer'. +** +** gctPOINTER StateBuffer +** Pointer to the states that make up the shader program. +** +** gcsHINT_PTR Hints +** Pointer to a gcsHINT structure that contains information required +** when loading the shader states. +*/ +gceSTATUS +gcLoadShaders( + IN gcoHAL Hal, + IN gctSIZE_T StateBufferSize, + IN gctPOINTER StateBuffer, + IN gcsHINT_PTR Hints + ); + +/******************************************************************************* +** gcSaveProgram +******************************************************************************** +** +** Save pre-compiled shaders and pre-linked programs to a binary file. +** +** INPUT: +** +** gcSHADER VertexShader +** Pointer to vertex shader object. +** +** gcSHADER FragmentShader +** Pointer to fragment shader object. +** +** gctSIZE_T ProgramBufferSize +** Number of bytes in 'ProgramBuffer'. +** +** gctPOINTER ProgramBuffer +** Pointer to buffer containing the program states. +** +** gcsHINT_PTR Hints +** Pointer to HINTS structure for program states. +** +** OUTPUT: +** +** gctPOINTER * Binary +** Pointer to a variable receiving the binary data to be saved. +** +** gctSIZE_T * BinarySize +** Pointer to a variable receiving the number of bytes inside 'Binary'. +*/ +gceSTATUS +gcSaveProgram( + IN gcSHADER VertexShader, + IN gcSHADER FragmentShader, + IN gctSIZE_T ProgramBufferSize, + IN gctPOINTER ProgramBuffer, + IN gcsHINT_PTR Hints, + OUT gctPOINTER * Binary, + OUT gctSIZE_T * BinarySize + ); + +/******************************************************************************* +** gcLoadProgram +******************************************************************************** +** +** Load pre-compiled shaders and pre-linked programs from a binary file. +** +** INPUT: +** +** gctPOINTER Binary +** Pointer to the binary data loaded. +** +** gctSIZE_T BinarySize +** Number of bytes in 'Binary'. +** +** OUTPUT: +** +** gcSHADER VertexShader +** Pointer to a vertex shader object. +** +** gcSHADER FragmentShader +** Pointer to a fragment shader object. +** +** gctSIZE_T * ProgramBufferSize +** Pointer to a variable receicing the number of bytes in the buffer +** returned in 'ProgramBuffer'. +** +** gctPOINTER * ProgramBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLoadProgram( + IN gctPOINTER Binary, + IN gctSIZE_T BinarySize, + OUT gcSHADER VertexShader, + OUT gcSHADER FragmentShader, + OUT gctSIZE_T * ProgramBufferSize, + OUT gctPOINTER * ProgramBuffer, + OUT gcsHINT_PTR * Hints + ); + +/******************************************************************************* +** gcCompileKernel +******************************************************************************** +** +** Compile a OpenCL kernel shader. +** +** INPUT: +** +** gcoOS Hal +** Pointer to an gcoHAL object. +** +** gctSIZE_T SourceSize +** Size of the source buffer in bytes. +** +** gctCONST_STRING Source +** Pointer to the buffer containing the shader source code. +** +** OUTPUT: +** +** gcSHADER * Binary +** Pointer to a variable receiving the pointer to a gcSHADER object +** containg the compiled shader code. +** +** gctSTRING * Log +** Pointer to a variable receiving a string pointer containging the +** compile log. +*/ +gceSTATUS +gcCompileKernel( + IN gcoHAL Hal, + IN gctSIZE_T SourceSize, + IN gctCONST_STRING Source, + IN gctCONST_STRING Options, + OUT gcSHADER * Binary, + OUT gctSTRING * Log + ); + +/******************************************************************************* +** gcLinkKernel +******************************************************************************** +** +** Link OpenCL kernel and generate a harwdare specific state buffer by compiling +** the compiler generated code through the resource allocator and code +** generator. +** +** INPUT: +** +** gcSHADER Kernel +** Pointer to a gcSHADER object holding information about the compiled +** OpenCL kernel. +** +** gceSHADER_FLAGS Flags +** Compiler flags. Can be any of the following: +** +** gcvSHADER_DEAD_CODE - Dead code elimination. +** gcvSHADER_RESOURCE_USAGE - Resource usage optimizaion. +** gcvSHADER_OPTIMIZER - Full optimization. +** gcvSHADER_USE_GL_Z - Use OpenGL ES Z coordinate. +** gcvSHADER_USE_GL_POSITION - Use OpenGL ES gl_Position. +** gcvSHADER_USE_GL_FACE - Use OpenGL ES gl_FaceForward. +** +** OUTPUT: +** +** gctSIZE_T * StateBufferSize +** Pointer to a variable receiving the number of bytes in the buffer +** returned in 'StateBuffer'. +** +** gctPOINTER * StateBuffer +** Pointer to a variable receiving a buffer pointer that contains the +** states required to download the shaders into the hardware. +** +** gcsHINT_PTR * Hints +** Pointer to a variable receiving a gcsHINT structure pointer that +** contains information required when loading the shader states. +*/ +gceSTATUS +gcLinkKernel( + IN gcSHADER Kernel, + IN gceSHADER_FLAGS Flags, + OUT gctSIZE_T * StateBufferSize, + OUT gctPOINTER * StateBuffer, + OUT gcsHINT_PTR * Hints + ); + +/******************************************************************************* +** gcLoadKernel +******************************************************************************** +** +** Load a pre-compiled and pre-linked kernel program into the hardware. +** +** INPUT: +** +** gctSIZE_T StateBufferSize +** The number of bytes in the 'StateBuffer'. +** +** gctPOINTER StateBuffer +** Pointer to the states that make up the shader program. +** +** gcsHINT_PTR Hints +** Pointer to a gcsHINT structure that contains information required +** when loading the shader states. +*/ +gceSTATUS +gcLoadKernel( + IN gctSIZE_T StateBufferSize, + IN gctPOINTER StateBuffer, + IN gcsHINT_PTR Hints + ); + +gceSTATUS +gcInvokeThreadWalker( + IN gcsTHREAD_WALKER_INFO_PTR Info + ); + +#ifdef __cplusplus +} +#endif + +#endif /* VIVANTE_NO_3D */ +#endif /* __gc_hal_compiler_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver.h new file mode 100644 index 0000000..7c9d163 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver.h @@ -0,0 +1,901 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_driver_h_ +#define __gc_hal_driver_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" + +#if gcdENABLE_VG +#include "gc_hal_driver_vg.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* I/O Control Codes ****************************** +\******************************************************************************/ + +#define gcvHAL_CLASS "galcore" +#define IOCTL_GCHAL_INTERFACE 30000 +#define IOCTL_GCHAL_KERNEL_INTERFACE 30001 +#define IOCTL_GCHAL_TERMINATE 30002 + +/******************************************************************************\ +********************************* Command Codes ******************************** +\******************************************************************************/ + +typedef enum _gceHAL_COMMAND_CODES +{ + /* Generic query. */ + gcvHAL_QUERY_VIDEO_MEMORY, + gcvHAL_QUERY_CHIP_IDENTITY, + + /* Contiguous memory. */ + gcvHAL_ALLOCATE_NON_PAGED_MEMORY, + gcvHAL_FREE_NON_PAGED_MEMORY, + gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY, + gcvHAL_FREE_CONTIGUOUS_MEMORY, + + /* Video memory allocation. */ + gcvHAL_ALLOCATE_VIDEO_MEMORY, /* Enforced alignment. */ + gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY, /* No alignment. */ + gcvHAL_FREE_VIDEO_MEMORY, + + /* Physical-to-logical mapping. */ + gcvHAL_MAP_MEMORY, + gcvHAL_UNMAP_MEMORY, + + /* Logical-to-physical mapping. */ + gcvHAL_MAP_USER_MEMORY, + gcvHAL_UNMAP_USER_MEMORY, + + /* Surface lock/unlock. */ + gcvHAL_LOCK_VIDEO_MEMORY, + gcvHAL_UNLOCK_VIDEO_MEMORY, + + /* Event queue. */ + gcvHAL_EVENT_COMMIT, + + gcvHAL_USER_SIGNAL, + gcvHAL_SIGNAL, + gcvHAL_WRITE_DATA, + + gcvHAL_COMMIT, + gcvHAL_STALL, + + gcvHAL_READ_REGISTER, + gcvHAL_WRITE_REGISTER, + + gcvHAL_GET_PROFILE_SETTING, + gcvHAL_SET_PROFILE_SETTING, + + gcvHAL_READ_ALL_PROFILE_REGISTERS, + gcvHAL_PROFILE_REGISTERS_2D, + + /* Power management. */ + gcvHAL_SET_POWER_MANAGEMENT_STATE, + gcvHAL_QUERY_POWER_MANAGEMENT_STATE, + + gcvHAL_GET_BASE_ADDRESS, + + gcvHAL_SET_IDLE, /* reserved */ + + /* Queries. */ + gcvHAL_QUERY_KERNEL_SETTINGS, + + /* Reset. */ + gcvHAL_RESET, + + /* Map physical address into handle. */ + gcvHAL_MAP_PHYSICAL, + + /* Debugger stuff. */ + gcvHAL_DEBUG, + + /* Cache stuff. */ + gcvHAL_CACHE, + + /* TimeStamp */ + gcvHAL_TIMESTAMP, + + /* Database. */ + gcvHAL_DATABASE, + + /* Version. */ + gcvHAL_VERSION, + + /* Chip info */ + gcvHAL_CHIP_INFO, + + /* Process attaching/detaching. */ + gcvHAL_ATTACH, + gcvHAL_DETACH, + + /* Composition. */ + gcvHAL_COMPOSE, + + /* Set timeOut value */ + gcvHAL_SET_TIMEOUT, + + /* Frame database. */ + gcvHAL_GET_FRAME_INFO, + + /* Shared info for each process */ + gcvHAL_GET_SHARED_INFO, + gcvHAL_SET_SHARED_INFO, + gcvHAL_QUERY_COMMAND_BUFFER, + + gcvHAL_COMMIT_DONE, + + /* GPU and event dump */ + gcvHAL_DUMP_GPU_STATE, + gcvHAL_DUMP_EVENT +} +gceHAL_COMMAND_CODES; + +/******************************************************************************\ +****************************** Interface Structure ***************************** +\******************************************************************************/ + +#define gcdMAX_PROFILE_FILE_NAME 128 + +/* Kernel settings. */ +typedef struct _gcsKERNEL_SETTINGS +{ + /* Used RealTime signal between kernel and user. */ + gctINT signal; +} +gcsKERNEL_SETTINGS; + + +/* gcvHAL_QUERY_CHIP_IDENTITY */ +typedef struct _gcsHAL_QUERY_CHIP_IDENTITY * gcsHAL_QUERY_CHIP_IDENTITY_PTR; +typedef struct _gcsHAL_QUERY_CHIP_IDENTITY +{ + + /* Chip model. */ + gceCHIPMODEL chipModel; + + /* Revision value.*/ + gctUINT32 chipRevision; + + /* Supported feature fields. */ + gctUINT32 chipFeatures; + + /* Supported minor feature fields. */ + gctUINT32 chipMinorFeatures; + + /* Supported minor feature 1 fields. */ + gctUINT32 chipMinorFeatures1; + + /* Supported minor feature 2 fields. */ + gctUINT32 chipMinorFeatures2; + + /* Supported minor feature 3 fields. */ + gctUINT32 chipMinorFeatures3; + + /* Number of streams supported. */ + gctUINT32 streamCount; + + /* Total number of temporary registers per thread. */ + gctUINT32 registerMax; + + /* Maximum number of threads. */ + gctUINT32 threadCount; + + /* Number of shader cores. */ + gctUINT32 shaderCoreCount; + + /* Size of the vertex cache. */ + gctUINT32 vertexCacheSize; + + /* Number of entries in the vertex output buffer. */ + gctUINT32 vertexOutputBufferSize; + + /* Number of pixel pipes. */ + gctUINT32 pixelPipes; + + /* Number of instructions. */ + gctUINT32 instructionCount; + + /* Number of constants. */ + gctUINT32 numConstants; + + /* Buffer size */ + gctUINT32 bufferSize; + +} +gcsHAL_QUERY_CHIP_IDENTITY; + +/* gcvHAL_COMPOSE. */ +typedef struct _gcsHAL_COMPOSE * gcsHAL_COMPOSE_PTR; +typedef struct _gcsHAL_COMPOSE +{ + /* Composition state buffer. */ + gctPHYS_ADDR physical; + gctPOINTER logical; + gctSIZE_T offset; + gctSIZE_T size; + + /* Composition end signal. */ + gctHANDLE process; + gctSIGNAL signal; + + /* User signals. */ + gctHANDLE userProcess; + gctSIGNAL userSignal1; + gctSIGNAL userSignal2; + +#if defined(__QNXNTO__) + /* Client pulse side-channel connection ID. */ + gctINT32 coid; + + /* Set by server. */ + gctINT32 rcvid; +#endif +} +gcsHAL_COMPOSE; + +typedef struct _gcsHAL_INTERFACE +{ + /* Command code. */ + gceHAL_COMMAND_CODES command; + + /* Hardware type. */ + gceHARDWARE_TYPE hardwareType; + + /* Status value. */ + gceSTATUS status; + + /* Handle to this interface channel. */ + gctHANDLE handle; + + /* Pid of the client. */ + gctUINT32 pid; + + /* Union of command structures. */ + union _u + { + /* gcvHAL_GET_BASE_ADDRESS */ + struct _gcsHAL_GET_BASE_ADDRESS + { + /* Physical memory address of internal memory. */ + OUT gctUINT32 baseAddress; + } + GetBaseAddress; + + /* gcvHAL_QUERY_VIDEO_MEMORY */ + struct _gcsHAL_QUERY_VIDEO_MEMORY + { + /* Physical memory address of internal memory. */ + OUT gctPHYS_ADDR internalPhysical; + + /* Size in bytes of internal memory.*/ + OUT gctSIZE_T internalSize; + + /* Physical memory address of external memory. */ + OUT gctPHYS_ADDR externalPhysical; + + /* Size in bytes of external memory.*/ + OUT gctSIZE_T externalSize; + + /* Physical memory address of contiguous memory. */ + OUT gctPHYS_ADDR contiguousPhysical; + + /* Size in bytes of contiguous memory.*/ + OUT gctSIZE_T contiguousSize; + } + QueryVideoMemory; + + /* gcvHAL_QUERY_CHIP_IDENTITY */ + gcsHAL_QUERY_CHIP_IDENTITY QueryChipIdentity; + + /* gcvHAL_MAP_MEMORY */ + struct _gcsHAL_MAP_MEMORY + { + /* Physical memory address to map. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to map. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory. */ + OUT gctPOINTER logical; + } + MapMemory; + + /* gcvHAL_UNMAP_MEMORY */ + struct _gcsHAL_UNMAP_MEMORY + { + /* Physical memory address to unmap. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to unmap. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory to unmap. */ + IN gctPOINTER logical; + } + UnmapMemory; + + /* gcvHAL_ALLOCATE_LINEAR_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_LINEAR_VIDEO_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctUINT bytes; + + /* Buffer alignment. */ + IN gctUINT alignment; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateLinearVideoMemory; + + /* gcvHAL_ALLOCATE_VIDEO_MEMORY */ + struct _gcsHAL_ALLOCATE_VIDEO_MEMORY + { + /* Width of rectangle to allocate. */ + IN OUT gctUINT width; + + /* Height of rectangle to allocate. */ + IN OUT gctUINT height; + + /* Depth of rectangle to allocate. */ + IN gctUINT depth; + + /* Format rectangle to allocate in gceSURF_FORMAT. */ + IN gceSURF_FORMAT format; + + /* Type of allocation. */ + IN gceSURF_TYPE type; + + /* Memory pool to allocate from. */ + IN OUT gcePOOL pool; + + /* Allocated video memory. */ + OUT gcuVIDMEM_NODE_PTR node; + } + AllocateVideoMemory; + + /* gcvHAL_FREE_VIDEO_MEMORY */ + struct _gcsHAL_FREE_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + +#ifdef __QNXNTO__ +/* TODO: This is part of the unlock - why is it here? */ + /* Mapped logical address to unmap in user space. */ + OUT gctPOINTER memory; + + /* Number of bytes to allocated. */ + OUT gctSIZE_T bytes; +#endif + } + FreeVideoMemory; + + /* gcvHAL_LOCK_VIDEO_MEMORY */ + struct _gcsHAL_LOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Cache configuration. */ + /* Only gcvPOOL_CONTIGUOUS and gcvPOOL_VIRUTAL + ** can be configured */ + IN gctBOOL cacheable; + + /* Hardware specific address. */ + OUT gctUINT32 address; + + /* Mapped logical address. */ + OUT gctPOINTER memory; + } + LockVideoMemory; + + /* gcvHAL_UNLOCK_VIDEO_MEMORY */ + struct _gcsHAL_UNLOCK_VIDEO_MEMORY + { + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; + + /* Type of surface. */ + IN gceSURF_TYPE type; + + /* Flag to unlock surface asynchroneously. */ + IN OUT gctBOOL asynchroneous; + } + UnlockVideoMemory; + + /* gcvHAL_ALLOCATE_NON_PAGED_MEMORY */ + struct _gcsHAL_ALLOCATE_NON_PAGED_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + } + AllocateNonPagedMemory; + + /* gcvHAL_FREE_NON_PAGED_MEMORY */ + struct _gcsHAL_FREE_NON_PAGED_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeNonPagedMemory; + + /* gcvHAL_EVENT_COMMIT. */ + struct _gcsHAL_EVENT_COMMIT + { + /* Event queue. */ + IN gcsQUEUE_PTR queue; + } + Event; + + /* gcvHAL_COMMIT */ + struct _gcsHAL_COMMIT + { + /* Context buffer object. */ + IN gckCONTEXT context; + + /* Command buffer. */ + IN gcoCMDBUF commandBuffer; + + /* State delta buffer. */ + gcsSTATE_DELTA_PTR delta; + + /* Event queue. */ + IN gcsQUEUE_PTR queue; + } + Commit; + + /* gcvHAL_MAP_USER_MEMORY */ + struct _gcsHAL_MAP_USER_MEMORY + { + /* Base address of user memory to map. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to map. */ + IN gctSIZE_T size; + + /* Info record required by gcvHAL_UNMAP_USER_MEMORY. */ + OUT gctPOINTER info; + + /* Physical address of mapped memory. */ + OUT gctUINT32 address; + } + MapUserMemory; + + /* gcvHAL_UNMAP_USER_MEMORY */ + struct _gcsHAL_UNMAP_USER_MEMORY + { + /* Base address of user memory to unmap. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to unmap. */ + IN gctSIZE_T size; + + /* Info record returned by gcvHAL_MAP_USER_MEMORY. */ + IN gctPOINTER info; + + /* Physical address of mapped memory as returned by + gcvHAL_MAP_USER_MEMORY. */ + IN gctUINT32 address; + } + UnmapUserMemory; +#if !USE_NEW_LINUX_SIGNAL + /* gcsHAL_USER_SIGNAL */ + struct _gcsHAL_USER_SIGNAL + { + /* Command. */ + gceUSER_SIGNAL_COMMAND_CODES command; + + /* Signal ID. */ + IN OUT gctINT id; + + /* Reset mode. */ + IN gctBOOL manualReset; + + /* Wait timedout. */ + IN gctUINT32 wait; + + /* State. */ + IN gctBOOL state; + } + UserSignal; +#endif + + /* gcvHAL_SIGNAL. */ + struct _gcsHAL_SIGNAL + { + /* Signal handle to signal. */ + IN gctSIGNAL signal; + + /* Reserved. */ + IN gctSIGNAL auxSignal; + + /* Process owning the signal. */ + IN gctHANDLE process; + +#if defined(__QNXNTO__) + /* Client pulse side-channel connection ID. Set by client in gcoOS_CreateSignal. */ + IN gctINT32 coid; + + /* Set by server. */ + IN gctINT32 rcvid; +#endif + /* Event generated from where of pipeline */ + IN gceKERNEL_WHERE fromWhere; + } + Signal; + + /* gcvHAL_WRITE_DATA. */ + struct _gcsHAL_WRITE_DATA + { + /* Address to write data to. */ + IN gctUINT32 address; + + /* Data to write. */ + IN gctUINT32 data; + } + WriteData; + + /* gcvHAL_ALLOCATE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_ALLOCATE_CONTIGUOUS_MEMORY + { + /* Number of bytes to allocate. */ + IN OUT gctSIZE_T bytes; + + /* Hardware address of allocation. */ + OUT gctUINT32 address; + + /* Physical address of allocation. */ + OUT gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + OUT gctPOINTER logical; + } + AllocateContiguousMemory; + + /* gcvHAL_FREE_CONTIGUOUS_MEMORY */ + struct _gcsHAL_FREE_CONTIGUOUS_MEMORY + { + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; + } + FreeContiguousMemory; + + /* gcvHAL_READ_REGISTER */ + struct _gcsHAL_READ_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + OUT gctUINT32 data; + } + ReadRegisterData; + + /* gcvHAL_WRITE_REGISTER */ + struct _gcsHAL_WRITE_REGISTER + { + /* Logical address of memory to write data to. */ + IN gctUINT32 address; + + /* Data read. */ + IN gctUINT32 data; + } + WriteRegisterData; + +#if VIVANTE_PROFILER + /* gcvHAL_GET_PROFILE_SETTING */ + struct _gcsHAL_GET_PROFILE_SETTING + { + /* Enable profiling */ + OUT gctBOOL enable; + + /* The profile file name */ + OUT gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + GetProfileSetting; + + /* gcvHAL_SET_PROFILE_SETTING */ + struct _gcsHAL_SET_PROFILE_SETTING + { + /* Enable profiling */ + IN gctBOOL enable; + + /* The profile file name */ + IN gctCHAR fileName[gcdMAX_PROFILE_FILE_NAME]; + } + SetProfileSetting; + + /* gcvHAL_READ_ALL_PROFILE_REGISTERS */ + struct _gcsHAL_READ_ALL_PROFILE_REGISTERS + { + /* Data read. */ + OUT gcsPROFILER_COUNTERS counters; + } + RegisterProfileData; + + /* gcvHAL_PROFILE_REGISTERS_2D */ + struct _gcsHAL_PROFILE_REGISTERS_2D + { + /* Data read. */ + OUT gcs2D_PROFILE_PTR hwProfile2D; + } + RegisterProfileData2D; +#endif + /* Power management. */ + /* gcvHAL_SET_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_SET_POWER_MANAGEMENT + { + /* Data read. */ + IN gceCHIPPOWERSTATE state; + } + SetPowerManagement; + + /* gcvHAL_QUERY_POWER_MANAGEMENT_STATE */ + struct _gcsHAL_QUERY_POWER_MANAGEMENT + { + /* Data read. */ + OUT gceCHIPPOWERSTATE state; + + /* Idle query. */ + OUT gctBOOL isIdle; + } + QueryPowerManagement; + + /* gcvHAL_QUERY_KERNEL_SETTINGS */ + struct _gcsHAL_QUERY_KERNEL_SETTINGS + { + /* Settings.*/ + OUT gcsKERNEL_SETTINGS settings; + } + QueryKernelSettings; + + /* gcvHAL_MAP_PHYSICAL */ + struct _gcsHAL_MAP_PHYSICAL + { + /* gcvTRUE to map, gcvFALSE to unmap. */ + IN gctBOOL map; + + /* Physical address. */ + IN OUT gctPHYS_ADDR physical; + } + MapPhysical; + + /* gcvHAL_DEBUG */ + struct _gcsHAL_DEBUG + { + /* If gcvTRUE, set the debug information. */ + IN gctBOOL set; + IN gctUINT32 level; + IN gctUINT32 zones; + IN gctBOOL enable; + + IN gceDEBUG_MESSAGE_TYPE type; + IN gctUINT32 messageSize; + + /* Message to print if not empty. */ + IN gctCHAR message[80]; + } + Debug; + + /* gcvHAL_CACHE */ + struct _gcsHAL_CACHE + { + IN gceCACHEOPERATION operation; + IN gctHANDLE process; + IN gctPOINTER logical; + IN gctSIZE_T bytes; + IN gcuVIDMEM_NODE_PTR node; + } + Cache; + + /* gcvHAL_TIMESTAMP */ + struct _gcsHAL_TIMESTAMP + { + /* Timer select. */ + IN gctUINT32 timer; + + /* Timer request type (0-stop, 1-start, 2-send delta). */ + IN gctUINT32 request; + + /* Result of delta time in microseconds. */ + OUT gctINT32 timeDelta; + } + TimeStamp; + + /* gcvHAL_DATABASE */ + struct _gcsHAL_DATABASE + { + /* Set to gcvTRUE if you want to query a particular process ID. + ** Set to gcvFALSE to query the last detached process. */ + IN gctBOOL validProcessID; + + /* Process ID to query. */ + IN gctUINT32 processID; + + /* Information. */ + OUT gcuDATABASE_INFO vidMem; + OUT gcuDATABASE_INFO nonPaged; + OUT gcuDATABASE_INFO contiguous; + OUT gcuDATABASE_INFO gpuIdle; + } + Database; + + /* gcvHAL_VERSION */ + struct _gcsHAL_VERSION + { + /* Major version: N.n.n. */ + OUT gctINT32 major; + + /* Minor version: n.N.n. */ + OUT gctINT32 minor; + + /* Patch version: n.n.N. */ + OUT gctINT32 patch; + + /* Build version. */ + OUT gctUINT32 build; + } + Version; + + /* gcvHAL_CHIP_INFO */ + struct _gcsHAL_CHIP_INFO + { + /* Chip count. */ + OUT gctINT32 count; + + /* Chip types. */ + OUT gceHARDWARE_TYPE types[gcdCHIP_COUNT]; + } + ChipInfo; + + /* gcvHAL_ATTACH */ + struct _gcsHAL_ATTACH + { + /* Context buffer object. */ + OUT gckCONTEXT context; + + /* Number of states in the buffer. */ + OUT gctSIZE_T stateCount; + } + Attach; + + /* gcvHAL_DETACH */ + struct _gcsHAL_DETACH + { + /* Context buffer object. */ + IN gckCONTEXT context; + } + Detach; + + /* gcvHAL_COMPOSE. */ + gcsHAL_COMPOSE Compose; + + /* gcvHAL_GET_FRAME_INFO. */ + struct _gcsHAL_GET_FRAME_INFO + { + OUT gcsHAL_FRAME_INFO * frameInfo; + } + GetFrameInfo; + + /* gcvHAL_SET_TIME_OUT. */ + struct _gcsHAL_SET_TIMEOUT + { + gctUINT32 timeOut; + } + SetTimeOut; + +#if gcdENABLE_VG + /* gcvHAL_COMMIT */ + struct _gcsHAL_VGCOMMIT + { + /* Context buffer. */ + IN gcsVGCONTEXT_PTR context; + + /* Command queue. */ + IN gcsVGCMDQUEUE_PTR queue; + + /* Number of entries in the queue. */ + IN gctUINT entryCount; + + /* Task table. */ + IN gcsTASK_MASTER_TABLE_PTR taskTable; + } + VGCommit; + + /* gcvHAL_QUERY_COMMAND_BUFFER */ + struct _gcsHAL_QUERY_COMMAND_BUFFER + { + /* Command buffer attributes. */ + OUT gcsCOMMAND_BUFFER_INFO information; + } + QueryCommandBuffer; + +#endif + + struct _gcsHAL_GET_SHARED_INFO + { + IN gctUINT32 pid; + IN gctUINT32 dataId; + IN gcuVIDMEM_NODE_PTR node; + OUT gctUINT8_PTR data; + /* fix size */ + OUT gctUINT8_PTR nodeData; + gctSIZE_T size; + IN gceVIDMEM_NODE_SHARED_INFO_TYPE infoType; + } + GetSharedInfo; + + struct _gcsHAL_SET_SHARED_INFO + { + IN gctUINT32 dataId; + IN gcuVIDMEM_NODE_PTR node; + IN gctUINT8_PTR data; + IN gctUINT8_PTR nodeData; + IN gctSIZE_T size; + IN gceVIDMEM_NODE_SHARED_INFO_TYPE infoType; + } + SetSharedInfo; + } + u; +} +gcsHAL_INTERFACE; + + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_driver_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver_vg.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver_vg.h new file mode 100644 index 0000000..fe57968 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_driver_vg.h @@ -0,0 +1,292 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + + + +#ifndef __gc_hal_driver_vg_h_ +#define __gc_hal_driver_vg_h_ + + + +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +******************************* I/O Control Codes ****************************** +\******************************************************************************/ + +#define gcvHAL_CLASS "galcore" +#define IOCTL_GCHAL_INTERFACE 30000 + +/******************************************************************************\ +********************************* Command Codes ******************************** +\******************************************************************************/ + +/******************************************************************************\ +********************* Command buffer information structure. ******************** +\******************************************************************************/ + +typedef struct _gcsCOMMAND_BUFFER_INFO * gcsCOMMAND_BUFFER_INFO_PTR; +typedef struct _gcsCOMMAND_BUFFER_INFO +{ + /* FE command buffer interrupt ID. */ + gctINT32 feBufferInt; + + /* TS overflow interrupt ID. */ + gctINT32 tsOverflowInt; + + /* Alignment and mask for the buffer address. */ + gctUINT addressMask; + gctSIZE_T addressAlignment; + + /* Alignment for each command. */ + gctSIZE_T commandAlignment; + + /* Number of bytes required by the STATE command. */ + gctSIZE_T stateCommandSize; + + /* Number of bytes required by the RESTART command. */ + gctSIZE_T restartCommandSize; + + /* Number of bytes required by the FETCH command. */ + gctSIZE_T fetchCommandSize; + + /* Number of bytes required by the CALL command. */ + gctSIZE_T callCommandSize; + + /* Number of bytes required by the RETURN command. */ + gctSIZE_T returnCommandSize; + + /* Number of bytes required by the EVENT command. */ + gctSIZE_T eventCommandSize; + + /* Number of bytes required by the END command. */ + gctSIZE_T endCommandSize; + + /* Number of bytes reserved at the tail of a static command buffer. */ + gctSIZE_T staticTailSize; + + /* Number of bytes reserved at the tail of a dynamic command buffer. */ + gctSIZE_T dynamicTailSize; +} +gcsCOMMAND_BUFFER_INFO; + +/******************************************************************************\ +******************************** Task Structures ******************************* +\******************************************************************************/ + +typedef enum _gceTASK +{ + gcvTASK_LINK, + gcvTASK_CLUSTER, + gcvTASK_INCREMENT, + gcvTASK_DECREMENT, + gcvTASK_SIGNAL, + gcvTASK_LOCKDOWN, + gcvTASK_UNLOCK_VIDEO_MEMORY, + gcvTASK_FREE_VIDEO_MEMORY, + gcvTASK_FREE_CONTIGUOUS_MEMORY, + gcvTASK_UNMAP_USER_MEMORY, + gcvTASK_UNMAP_MEMORY +} +gceTASK; + +typedef struct _gcsTASK_HEADER * gcsTASK_HEADER_PTR; +typedef struct _gcsTASK_HEADER +{ + /* Task ID. */ + IN gceTASK id; +} +gcsTASK_HEADER; + +typedef struct _gcsTASK_LINK * gcsTASK_LINK_PTR; +typedef struct _gcsTASK_LINK +{ + /* Task ID (gcvTASK_LINK). */ + IN gceTASK id; + + /* Pointer to the next task container. */ + IN gctPOINTER cotainer; + + /* Pointer to the next task from the next task container. */ + IN gcsTASK_HEADER_PTR task; +} +gcsTASK_LINK; + +typedef struct _gcsTASK_CLUSTER * gcsTASK_CLUSTER_PTR; +typedef struct _gcsTASK_CLUSTER +{ + /* Task ID (gcvTASK_CLUSTER). */ + IN gceTASK id; + + /* Number of tasks in the cluster. */ + IN gctUINT taskCount; +} +gcsTASK_CLUSTER; + +typedef struct _gcsTASK_INCREMENT * gcsTASK_INCREMENT_PTR; +typedef struct _gcsTASK_INCREMENT +{ + /* Task ID (gcvTASK_INCREMENT). */ + IN gceTASK id; + + /* Address of the variable to increment. */ + IN gctUINT32 address; +} +gcsTASK_INCREMENT; + +typedef struct _gcsTASK_DECREMENT * gcsTASK_DECREMENT_PTR; +typedef struct _gcsTASK_DECREMENT +{ + /* Task ID (gcvTASK_DECREMENT). */ + IN gceTASK id; + + /* Address of the variable to decrement. */ + IN gctUINT32 address; +} +gcsTASK_DECREMENT; + +typedef struct _gcsTASK_SIGNAL * gcsTASK_SIGNAL_PTR; +typedef struct _gcsTASK_SIGNAL +{ + /* Task ID (gcvTASK_SIGNAL). */ + IN gceTASK id; + + /* Process owning the signal. */ + IN gctHANDLE process; + + /* Signal handle to signal. */ + IN gctSIGNAL signal; + +#if defined(__QNXNTO__) + IN gctINT32 coid; + IN gctINT32 rcvid; +#endif +} +gcsTASK_SIGNAL; + +typedef struct _gcsTASK_LOCKDOWN * gcsTASK_LOCKDOWN_PTR; +typedef struct _gcsTASK_LOCKDOWN +{ + /* Task ID (gcvTASK_LOCKDOWN). */ + IN gceTASK id; + + /* Address of the user space counter. */ + IN gctUINT32 userCounter; + + /* Address of the kernel space counter. */ + IN gctUINT32 kernelCounter; + + /* Process owning the signal. */ + IN gctHANDLE process; + + /* Signal handle to signal. */ + IN gctSIGNAL signal; +} +gcsTASK_LOCKDOWN; + +typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY * gcsTASK_UNLOCK_VIDEO_MEMORY_PTR; +typedef struct _gcsTASK_UNLOCK_VIDEO_MEMORY +{ + /* Task ID (gcvTASK_UNLOCK_VIDEO_MEMORY). */ + IN gceTASK id; + + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; +} +gcsTASK_UNLOCK_VIDEO_MEMORY; + +typedef struct _gcsTASK_FREE_VIDEO_MEMORY * gcsTASK_FREE_VIDEO_MEMORY_PTR; +typedef struct _gcsTASK_FREE_VIDEO_MEMORY +{ + /* Task ID (gcvTASK_FREE_VIDEO_MEMORY). */ + IN gceTASK id; + + /* Allocated video memory. */ + IN gcuVIDMEM_NODE_PTR node; +} +gcsTASK_FREE_VIDEO_MEMORY; + +typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY * gcsTASK_FREE_CONTIGUOUS_MEMORY_PTR; +typedef struct _gcsTASK_FREE_CONTIGUOUS_MEMORY +{ + /* Task ID (gcvTASK_FREE_CONTIGUOUS_MEMORY). */ + IN gceTASK id; + + /* Number of bytes allocated. */ + IN gctSIZE_T bytes; + + /* Physical address of allocation. */ + IN gctPHYS_ADDR physical; + + /* Logical address of allocation. */ + IN gctPOINTER logical; +} +gcsTASK_FREE_CONTIGUOUS_MEMORY; + +typedef struct _gcsTASK_UNMAP_USER_MEMORY * gcsTASK_UNMAP_USER_MEMORY_PTR; +typedef struct _gcsTASK_UNMAP_USER_MEMORY +{ + /* Task ID (gcvTASK_UNMAP_USER_MEMORY). */ + IN gceTASK id; + + /* Base address of user memory to unmap. */ + IN gctPOINTER memory; + + /* Size of user memory in bytes to unmap. */ + IN gctSIZE_T size; + + /* Info record returned by gcvHAL_MAP_USER_MEMORY. */ + IN gctPOINTER info; + + /* Physical address of mapped memory as returned by + gcvHAL_MAP_USER_MEMORY. */ + IN gctUINT32 address; +} +gcsTASK_UNMAP_USER_MEMORY; + +typedef struct _gcsTASK_UNMAP_MEMORY * gcsTASK_UNMAP_MEMORY_PTR; +typedef struct _gcsTASK_UNMAP_MEMORY +{ + /* Task ID (gcvTASK_UNMAP_MEMORY). */ + IN gceTASK id; + + /* Physical memory address to unmap. */ + IN gctPHYS_ADDR physical; + + /* Number of bytes in physical memory to unmap. */ + IN gctSIZE_T bytes; + + /* Address of mapped memory to unmap. */ + IN gctPOINTER logical; +} +gcsTASK_UNMAP_MEMORY; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_driver_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_dump.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_dump.h new file mode 100644 index 0000000..9b2db22 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_dump.h @@ -0,0 +1,89 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + +#ifndef __gc_hal_dump_h_ +#define __gc_hal_dump_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** FILE LAYOUT: +** +** gcsDUMP_FILE structure +** +** gcsDUMP_DATA frame +** gcsDUMP_DATA or gcDUMP_DATA_SIZE records rendingring the frame +** gctUINT8 data[length] +*/ + +#define gcvDUMP_FILE_SIGNATURE gcmCC('g','c','D','B') + +typedef struct _gcsDUMP_FILE +{ + gctUINT32 signature; /* File signature */ + gctSIZE_T length; /* Length of file */ + gctUINT32 frames; /* Number of frames in file */ +} +gcsDUMP_FILE; + +typedef enum _gceDUMP_TAG +{ + gcvTAG_SURFACE = gcmCC('s','u','r','f'), + gcvTAG_FRAME = gcmCC('f','r','m',' '), + gcvTAG_COMMAND = gcmCC('c','m','d',' '), + gcvTAG_INDEX = gcmCC('i','n','d','x'), + gcvTAG_STREAM = gcmCC('s','t','r','m'), + gcvTAG_TEXTURE = gcmCC('t','e','x','t'), + gcvTAG_RENDER_TARGET = gcmCC('r','n','d','r'), + gcvTAG_DEPTH = gcmCC('z','b','u','f'), + gcvTAG_RESOLVE = gcmCC('r','s','l','v'), + gcvTAG_DELETE = gcmCC('d','e','l',' '), +} +gceDUMP_TAG; + +typedef struct _gcsDUMP_SURFACE +{ + gceDUMP_TAG type; /* Type of record. */ + gctUINT32 address; /* Address of the surface. */ + gctINT16 width; /* Width of surface. */ + gctINT16 height; /* Height of surface. */ + gceSURF_FORMAT format; /* Surface pixel format. */ + gctSIZE_T length; /* Number of bytes inside the surface. */ +} +gcsDUMP_SURFACE; + +typedef struct _gcsDUMP_DATA +{ + gceDUMP_TAG type; /* Type of record. */ + gctSIZE_T length; /* Number of bytes of data. */ + gctUINT32 address; /* Address for the data. */ +} +gcsDUMP_DATA; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_dump_h_ */ + diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_eglplatform.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_eglplatform.h new file mode 100644 index 0000000..e0efba4 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_eglplatform.h @@ -0,0 +1,621 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_eglplatform_h_ +#define __gc_hal_eglplatform_h_ + +/* Include VDK types. */ +#include "gc_hal_types.h" +#include "gc_hal_base.h" +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* +** Events. ********************************************************************* +*/ + +typedef enum _halEventType +{ + /* Keyboard event. */ + HAL_KEYBOARD, + + /* Mouse move event. */ + HAL_POINTER, + + /* Mouse button event. */ + HAL_BUTTON, + + /* Application close event. */ + HAL_CLOSE, + + /* Application window has been updated. */ + HAL_WINDOW_UPDATE +} +halEventType; + +/* Scancodes for keyboard. */ +typedef enum _halKeys +{ + HAL_UNKNOWN = -1, + + HAL_BACKSPACE = 0x08, + HAL_TAB, + HAL_ENTER = 0x0D, + HAL_ESCAPE = 0x1B, + + HAL_SPACE = 0x20, + HAL_SINGLEQUOTE = 0x27, + HAL_PAD_ASTERISK = 0x2A, + HAL_COMMA = 0x2C, + HAL_HYPHEN, + HAL_PERIOD, + HAL_SLASH, + HAL_0, + HAL_1, + HAL_2, + HAL_3, + HAL_4, + HAL_5, + HAL_6, + HAL_7, + HAL_8, + HAL_9, + HAL_SEMICOLON = 0x3B, + HAL_EQUAL = 0x3D, + HAL_A = 0x41, + HAL_B, + HAL_C, + HAL_D, + HAL_E, + HAL_F, + HAL_G, + HAL_H, + HAL_I, + HAL_J, + HAL_K, + HAL_L, + HAL_M, + HAL_N, + HAL_O, + HAL_P, + HAL_Q, + HAL_R, + HAL_S, + HAL_T, + HAL_U, + HAL_V, + HAL_W, + HAL_X, + HAL_Y, + HAL_Z, + HAL_LBRACKET, + HAL_BACKSLASH, + HAL_RBRACKET, + HAL_BACKQUOTE = 0x60, + + HAL_F1 = 0x80, + HAL_F2, + HAL_F3, + HAL_F4, + HAL_F5, + HAL_F6, + HAL_F7, + HAL_F8, + HAL_F9, + HAL_F10, + HAL_F11, + HAL_F12, + + HAL_LCTRL, + HAL_RCTRL, + HAL_LSHIFT, + HAL_RSHIFT, + HAL_LALT, + HAL_RALT, + HAL_CAPSLOCK, + HAL_NUMLOCK, + HAL_SCROLLLOCK, + HAL_PAD_0, + HAL_PAD_1, + HAL_PAD_2, + HAL_PAD_3, + HAL_PAD_4, + HAL_PAD_5, + HAL_PAD_6, + HAL_PAD_7, + HAL_PAD_8, + HAL_PAD_9, + HAL_PAD_HYPHEN, + HAL_PAD_PLUS, + HAL_PAD_SLASH, + HAL_PAD_PERIOD, + HAL_PAD_ENTER, + HAL_SYSRQ, + HAL_PRNTSCRN, + HAL_BREAK, + HAL_UP, + HAL_LEFT, + HAL_RIGHT, + HAL_DOWN, + HAL_HOME, + HAL_END, + HAL_PGUP, + HAL_PGDN, + HAL_INSERT, + HAL_DELETE, + HAL_LWINDOW, + HAL_RWINDOW, + HAL_MENU, + HAL_POWER, + HAL_SLEEP, + HAL_WAKE +} +halKeys; + +/* Structure that defined keyboard mapping. */ +typedef struct _halKeyMap +{ + /* Normal key. */ + halKeys normal; + + /* Extended key. */ + halKeys extended; +} +halKeyMap; + +/* Event structure. */ +typedef struct _halEvent +{ + /* Event type. */ + halEventType type; + + /* Event data union. */ + union _halEventData + { + /* Event data for keyboard. */ + struct _halKeyboard + { + /* Scancode. */ + halKeys scancode; + + /* ASCII characte of the key pressed. */ + gctCHAR key; + + /* Flag whether the key was pressed (1) or released (0). */ + gctCHAR pressed; + } + keyboard; + + /* Event data for pointer. */ + struct _halPointer + { + /* Current pointer coordinate. */ + gctINT x; + gctINT y; + } + pointer; + + /* Event data for mouse buttons. */ + struct _halButton + { + /* Left button state. */ + gctINT left; + + /* Middle button state. */ + gctINT middle; + + /* Right button state. */ + gctINT right; + + /* Current pointer coordinate. */ + gctINT x; + gctINT y; + } + button; + } + data; +} +halEvent; + +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) +/* Win32 and Windows CE platforms. */ +#include <windows.h> +typedef HDC HALNativeDisplayType; +typedef HWND HALNativeWindowType; +typedef HBITMAP HALNativePixmapType; + +#elif defined(LINUX) && defined(EGL_API_FB) && !defined(__APPLE__) +/* Linux platform for FBDEV. */ +typedef struct _FBDisplay * HALNativeDisplayType; +typedef struct _FBWindow * HALNativeWindowType; +typedef struct _FBPixmap * HALNativePixmapType; + +#elif defined(__ANDROID__) || defined(ANDROID) + +struct egl_native_pixmap_t; + +#if ANDROID_SDK_VERSION >= 9 + #include <android/native_window.h> + + typedef struct ANativeWindow* HALNativeWindowType; + typedef struct egl_native_pixmap_t* HALNativePixmapType; + typedef void* HALNativeDisplayType; +#else + struct android_native_window_t; + typedef struct android_native_window_t* HALNativeWindowType; + typedef struct egl_native_pixmap_t * HALNativePixmapType; + typedef void* HALNativeDisplayType; +#endif + +#elif defined(LINUX) || defined(__APPLE__) +/* X11 platform. */ +#include <X11/Xlib.h> +#include <X11/Xutil.h> + +typedef Display * HALNativeDisplayType; +typedef Window HALNativeWindowType; + +#ifdef CUSTOM_PIXMAP +typedef void * HALNativePixmapType; +#else +typedef Pixmap HALNativePixmapType; +#endif /* CUSTOM_PIXMAP */ + +/* Rename some badly named X defines. */ +#ifdef Status +# define XStatus int +# undef Status +#endif +#ifdef Always +# define XAlways 2 +# undef Always +#endif +#ifdef CurrentTime +# undef CurrentTime +# define XCurrentTime 0 +#endif + +#elif defined(__QNXNTO__) + +/* VOID */ +typedef void * HALNativeDisplayType; +typedef void * HALNativeWindowType; +typedef void * HALNativePixmapType; + +#else + +#error "Platform not recognized" + +/* VOID */ +typedef void * HALNativeDisplayType; +typedef void * HALNativeWindowType; +typedef void * HALNativePixmapType; + +#endif + + + +/******************************************************************************* +** Display. ******************************************************************** +*/ + +gceSTATUS +gcoOS_GetDisplay( + OUT HALNativeDisplayType * Display + ); + +gceSTATUS +gcoOS_GetDisplayByIndex( + IN gctINT DisplayIndex, + OUT HALNativeDisplayType * Display + ); + +gceSTATUS +gcoOS_GetDisplayInfo( + IN HALNativeDisplayType Display, + OUT gctINT * Width, + OUT gctINT * Height, + OUT gctSIZE_T * Physical, + OUT gctINT * Stride, + OUT gctINT * BitsPerPixel + ); + +/* VFK_DISPLAY_INFO structure defining information returned by + vdkGetDisplayInfoEx. */ +typedef struct _halDISPLAY_INFO +{ + /* The size of the display in pixels. */ + gctINT width; + gctINT height; + + /* The stride of the dispay. -1 is returned if the stride is not known + ** for the specified display.*/ + gctINT stride; + + /* The color depth of the display in bits per pixel. */ + gctINT bitsPerPixel; + + /* The logical pointer to the display memory buffer. NULL is returned + ** if the pointer is not known for the specified display. */ + gctPOINTER logical; + + /* The physical address of the display memory buffer. ~0 is returned + ** if the address is not known for the specified display. */ + gctSIZE_T physical; + +#ifndef __QNXNTO__ + /* 355_FB_MULTI_BUFFER */ + gctINT multiBuffer; + gctINT backBufferY; +#endif + + /* The color info of the display. */ + gctUINT alphaLength; + gctUINT alphaOffset; + gctUINT redLength; + gctUINT redOffset; + gctUINT greenLength; + gctUINT greenOffset; + gctUINT blueLength; + gctUINT blueOffset; + + /* Display flip support. */ + gctINT flip; +} +halDISPLAY_INFO; + +gceSTATUS +gcoOS_GetDisplayInfoEx( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctUINT DisplayInfoSize, + OUT halDISPLAY_INFO * DisplayInfo + ); + +gceSTATUS +gcoOS_GetNextDisplayInfoEx( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctUINT DisplayInfoSize, + OUT halDISPLAY_INFO * DisplayInfo + ); + +gceSTATUS +gcoOS_GetDisplayVirtual( + IN HALNativeDisplayType Display, + OUT gctINT * Width, + OUT gctINT * Height + ); + +gceSTATUS +gcoOS_GetDisplayBackbuffer( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctPOINTER context, + IN gcoSURF surface, + OUT gctUINT * Offset, + OUT gctINT * X, + OUT gctINT * Y + ); + +gceSTATUS +gcoOS_SetDisplayVirtual( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctUINT Offset, + IN gctINT X, + IN gctINT Y + ); + +gceSTATUS +gcoOS_DisplayBufferRegions( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctINT NumRects, + IN gctINT_PTR Rects + ); + +gceSTATUS +gcoOS_DestroyDisplay( + IN HALNativeDisplayType Display + ); + +/******************************************************************************* +** Windows. ******************************************************************** +*/ + +gceSTATUS +gcoOS_CreateWindow( + IN HALNativeDisplayType Display, + IN gctINT X, + IN gctINT Y, + IN gctINT Width, + IN gctINT Height, + OUT HALNativeWindowType * Window + ); + +gceSTATUS +gcoOS_GetWindowInfo( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + OUT gctINT * X, + OUT gctINT * Y, + OUT gctINT * Width, + OUT gctINT * Height, + OUT gctINT * BitsPerPixel, +#ifdef __QNXNTO__ + OUT gctINT * Format, +#endif + OUT gctUINT * Offset + ); + +gceSTATUS +gcoOS_DestroyWindow( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window + ); + +gceSTATUS +gcoOS_DrawImage( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + IN gctINT Width, + IN gctINT Height, + IN gctINT BitsPerPixel, + IN gctPOINTER Bits + ); + +gceSTATUS +gcoOS_GetImage( + IN HALNativeWindowType Window, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + OUT gctINT * BitsPerPixel, + OUT gctPOINTER * Bits + ); + +/******************************************************************************* +** Pixmaps. ******************************************************************** +*/ + +gceSTATUS +gcoOS_CreatePixmap( + IN HALNativeDisplayType Display, + IN gctINT Width, + IN gctINT Height, + IN gctINT BitsPerPixel, + OUT HALNativePixmapType * Pixmap + ); + +gceSTATUS +gcoOS_GetPixmapInfo( + IN HALNativeDisplayType Display, + IN HALNativePixmapType Pixmap, + OUT gctINT * Width, + OUT gctINT * Height, + OUT gctINT * BitsPerPixel, + OUT gctINT * Stride, + OUT gctPOINTER * Bits + ); + +gceSTATUS +gcoOS_DrawPixmap( + IN HALNativeDisplayType Display, + IN HALNativePixmapType Pixmap, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + IN gctINT Width, + IN gctINT Height, + IN gctINT BitsPerPixel, + IN gctPOINTER Bits + ); + +gceSTATUS +gcoOS_DestroyPixmap( + IN HALNativeDisplayType Display, + IN HALNativePixmapType Pixmap + ); + +/******************************************************************************* +** OS relative. **************************************************************** +*/ +gceSTATUS +gcoOS_LoadEGLLibrary( + OUT gctHANDLE * Handle + ); + +gceSTATUS +gcoOS_FreeEGLLibrary( + IN gctHANDLE Handle + ); + +gceSTATUS +gcoOS_ShowWindow( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window + ); + +gceSTATUS +gcoOS_HideWindow( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window + ); + +gceSTATUS +gcoOS_SetWindowTitle( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + IN gctCONST_STRING Title + ); + +gceSTATUS +gcoOS_CapturePointer( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window + ); + +gceSTATUS +gcoOS_GetEvent( + IN HALNativeDisplayType Display, + IN HALNativeWindowType Window, + OUT halEvent * Event + ); + +gceSTATUS +gcoOS_CreateClientBuffer( + IN gctINT Width, + IN gctINT Height, + IN gctINT Format, + IN gctINT Type, + OUT gctPOINTER * ClientBuffer + ); + +gceSTATUS +gcoOS_GetClientBufferInfo( + IN gctPOINTER ClientBuffer, + OUT gctINT * Width, + OUT gctINT * Height, + OUT gctINT * Stride, + OUT gctPOINTER * Bits + ); + +gceSTATUS +gcoOS_DestroyClientBuffer( + IN gctPOINTER ClientBuffer + ); + + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_eglplatform_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine.h new file mode 100644 index 0000000..22cdc2f --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine.h @@ -0,0 +1,1847 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_engine_h_ +#define __gc_hal_engine_h_ + +#ifndef VIVANTE_NO_3D +#include "gc_hal_types.h" +#include "gc_hal_enum.h" + +#if gcdENABLE_VG +#include "gc_hal_engine_vg.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoSTREAM * gcoSTREAM; +typedef struct _gcoVERTEX * gcoVERTEX; +typedef struct _gcoTEXTURE * gcoTEXTURE; +typedef struct _gcoINDEX * gcoINDEX; +typedef struct _gcsVERTEX_ATTRIBUTES * gcsVERTEX_ATTRIBUTES_PTR; +typedef struct _gcoVERTEXARRAY * gcoVERTEXARRAY; + +#define gcdATTRIBUTE_COUNT 16 + +/******************************************************************************\ +********************************* Enumerations ********************************* +\******************************************************************************/ + +/* Shading format. */ +typedef enum _gceSHADING +{ + gcvSHADING_SMOOTH, + gcvSHADING_FLAT_D3D, + gcvSHADING_FLAT_OPENGL, +} +gceSHADING; + +/* Culling modes. */ +typedef enum _gceCULL +{ + gcvCULL_NONE, + gcvCULL_CCW, + gcvCULL_CW, +} +gceCULL; + +/* Fill modes. */ +typedef enum _gceFILL +{ + gcvFILL_POINT, + gcvFILL_WIRE_FRAME, + gcvFILL_SOLID, +} +gceFILL; + +/* Compare modes. */ +typedef enum _gceCOMPARE +{ + gcvCOMPARE_NEVER, + gcvCOMPARE_NOT_EQUAL, + gcvCOMPARE_LESS, + gcvCOMPARE_LESS_OR_EQUAL, + gcvCOMPARE_EQUAL, + gcvCOMPARE_GREATER, + gcvCOMPARE_GREATER_OR_EQUAL, + gcvCOMPARE_ALWAYS, + gcvCOMPARE_INVALID = -1 +} +gceCOMPARE; + +/* Stencil modes. */ +typedef enum _gceSTENCIL_MODE +{ + gcvSTENCIL_NONE, + gcvSTENCIL_SINGLE_SIDED, + gcvSTENCIL_DOUBLE_SIDED, +} +gceSTENCIL_MODE; + +/* Stencil operations. */ +typedef enum _gceSTENCIL_OPERATION +{ + gcvSTENCIL_KEEP, + gcvSTENCIL_REPLACE, + gcvSTENCIL_ZERO, + gcvSTENCIL_INVERT, + gcvSTENCIL_INCREMENT, + gcvSTENCIL_DECREMENT, + gcvSTENCIL_INCREMENT_SATURATE, + gcvSTENCIL_DECREMENT_SATURATE, + gcvSTENCIL_OPERATION_INVALID = -1 +} +gceSTENCIL_OPERATION; + +/* Stencil selection. */ +typedef enum _gceSTENCIL_WHERE +{ + gcvSTENCIL_FRONT, + gcvSTENCIL_BACK, +} +gceSTENCIL_WHERE; + +/* Texture addressing selection. */ +typedef enum _gceTEXTURE_WHICH +{ + gcvTEXTURE_S, + gcvTEXTURE_T, + gcvTEXTURE_R, +} +gceTEXTURE_WHICH; + +/* Texture addressing modes. */ +typedef enum _gceTEXTURE_ADDRESSING +{ + gcvTEXTURE_WRAP, + gcvTEXTURE_CLAMP, + gcvTEXTURE_BORDER, + gcvTEXTURE_MIRROR, + gcvTEXTURE_MIRROR_ONCE, +} +gceTEXTURE_ADDRESSING; + +/* Texture filters. */ +typedef enum _gceTEXTURE_FILTER +{ + gcvTEXTURE_NONE, + gcvTEXTURE_POINT, + gcvTEXTURE_LINEAR, + gcvTEXTURE_ANISOTROPIC, +} +gceTEXTURE_FILTER; + +/* Primitive types. */ +typedef enum _gcePRIMITIVE +{ + gcvPRIMITIVE_POINT_LIST, + gcvPRIMITIVE_LINE_LIST, + gcvPRIMITIVE_LINE_STRIP, + gcvPRIMITIVE_LINE_LOOP, + gcvPRIMITIVE_TRIANGLE_LIST, + gcvPRIMITIVE_TRIANGLE_STRIP, + gcvPRIMITIVE_TRIANGLE_FAN, + gcvPRIMITIVE_RECTANGLE, +} +gcePRIMITIVE; + +/* Index types. */ +typedef enum _gceINDEX_TYPE +{ + gcvINDEX_8, + gcvINDEX_16, + gcvINDEX_32, +} +gceINDEX_TYPE; + +/******************************************************************************\ +********************************* gcoHAL Object ********************************* +\******************************************************************************/ + +/* Query the target capabilities. */ +gceSTATUS +gcoHAL_QueryTargetCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MultiTargetCount, + OUT gctUINT * MaxSamples + ); + +gceSTATUS +gcoHAL_SetDepthOnly( + IN gcoHAL Hal, + IN gctBOOL Enable + ); + +gceSTATUS +gcoHAL_QueryShaderCaps( + IN gcoHAL Hal, + OUT gctUINT * VertexUniforms, + OUT gctUINT * FragmentUniforms, + OUT gctUINT * Varyings + ); + +gceSTATUS +gcoHAL_QueryTextureCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoHAL_QueryTextureMaxAniso( + IN gcoHAL Hal, + OUT gctUINT * MaxAnisoValue + ); + +gceSTATUS +gcoHAL_QueryStreamCaps( + IN gcoHAL Hal, + OUT gctUINT32 * MaxAttributes, + OUT gctUINT32 * MaxStreamSize, + OUT gctUINT32 * NumberOfStreams, + OUT gctUINT32 * Alignment + ); + +/******************************************************************************\ +********************************* gcoSURF Object ******************************** +\******************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/*--------------------------------- gcoSURF 3D --------------------------------*/ + +/* Copy surface. */ +gceSTATUS +gcoSURF_Copy( + IN gcoSURF Surface, + IN gcoSURF Source + ); + +/* Clear surface. */ +gceSTATUS +gcoSURF_Clear( + IN gcoSURF Surface, + IN gctUINT Flags + ); + +/* Set number of samples for a gcoSURF object. */ +gceSTATUS +gcoSURF_SetSamples( + IN gcoSURF Surface, + IN gctUINT Samples + ); + +/* Get the number of samples per pixel. */ +gceSTATUS +gcoSURF_GetSamples( + IN gcoSURF Surface, + OUT gctUINT_PTR Samples + ); + +/* Clear rectangular surface. */ +gceSTATUS +gcoSURF_ClearRect( + IN gcoSURF Surface, + IN gctINT Left, + IN gctINT Top, + IN gctINT Right, + IN gctINT Bottom, + IN gctUINT Flags + ); + +/* TO BE REMOVED */ + gceSTATUS + depr_gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight + ); + + gceSTATUS + depr_gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 DestAddress, + IN gctPOINTER DestBits, + IN gctINT DestStride, + IN gceSURF_TYPE DestType, + IN gceSURF_FORMAT DestFormat, + IN gctUINT DestWidth, + IN gctUINT DestHeight, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); + +/* Resample surface. */ +gceSTATUS +gcoSURF_Resample( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Resolve surface. */ +gceSTATUS +gcoSURF_Resolve( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Export the render target. */ +gceSTATUS +gcoSURF_ExportRenderTarget( + IN gcoSURF SrcSurface +); + +/* Import the render target. */ +gceSTATUS +gcoSURF_ImportRenderTarget( + IN gctUINT32 Pid, + IN gcoSURF SrcSurface +); + +/* Save the Resolve info to kernel. */ +gceSTATUS +gcoSURF_PrepareRemoteResolveRect( + IN gcoSURF SrcSurface, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); + +/* Resolve using the rectangle info previously saved in the vid mem node. */ +gceSTATUS +gcoSURF_ResolveFromStoredRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface + ); + +/* Using the info that Process Pid saved to do resolve. */ +gceSTATUS +gcoSURF_RemoteResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctBOOL *resolveDiscarded + ); + +/* Return the "resolve submitted indicator" signal. */ +gceSTATUS +gcoSURF_GetRTSignal( + IN gcoSURF RTSurface, + OUT gctSIGNAL * resolveSubmittedSignal + ); + +/* Resolve rectangular area of a surface. */ +gceSTATUS +gcoSURF_ResolveRect( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsPOINT_PTR SrcOrigin, + IN gcsPOINT_PTR DestOrigin, + IN gcsPOINT_PTR RectSize + ); + +/* Set surface resolvability. */ +gceSTATUS +gcoSURF_SetResolvability( + IN gcoSURF Surface, + IN gctBOOL Resolvable + ); + +gceSTATUS +gcoSURF_IsRenderable( + IN gcoSURF Surface + ); + +/******************************************************************************\ +******************************** gcoINDEX Object ******************************* +\******************************************************************************/ + +/* Construct a new gcoINDEX object. */ +gceSTATUS +gcoINDEX_Construct( + IN gcoHAL Hal, + OUT gcoINDEX * Index + ); + +/* Destroy a gcoINDEX object. */ +gceSTATUS +gcoINDEX_Destroy( + IN gcoINDEX Index + ); + +/* Lock index in memory. */ +gceSTATUS +gcoINDEX_Lock( + IN gcoINDEX Index, + OUT gctUINT32 * Address, + OUT gctPOINTER * Memory + ); + +/* Unlock index that was previously locked with gcoINDEX_Lock. */ +gceSTATUS +gcoINDEX_Unlock( + IN gcoINDEX Index + ); + +/* Upload index data into the memory. */ +gceSTATUS +gcoINDEX_Load( + IN gcoINDEX Index, + IN gceINDEX_TYPE IndexType, + IN gctUINT32 IndexCount, + IN gctPOINTER IndexBuffer + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_Bind( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type + ); + +/* Bind an index object to the hardware. */ +gceSTATUS +gcoINDEX_BindOffset( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset + ); + +/* Free existing index buffer. */ +gceSTATUS +gcoINDEX_Free( + IN gcoINDEX Index + ); + +/* Upload data into an index buffer. */ +gceSTATUS +gcoINDEX_Upload( + IN gcoINDEX Index, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Upload data into an index buffer starting at an offset. */ +gceSTATUS +gcoINDEX_UploadOffset( + IN gcoINDEX Index, + IN gctUINT32 Offset, + IN gctCONST_POINTER Buffer, + IN gctSIZE_T Bytes + ); + +/* Query the index capabilities. */ +gceSTATUS +gcoINDEX_QueryCaps( + OUT gctBOOL * Index8, + OUT gctBOOL * Index16, + OUT gctBOOL * Index32, + OUT gctUINT * MaxIndex + ); + +/* Determine the index range in the current index buffer. */ +gceSTATUS +gcoINDEX_GetIndexRange( + IN gcoINDEX Index, + IN gceINDEX_TYPE Type, + IN gctUINT32 Offset, + IN gctUINT32 Count, + OUT gctUINT32 * MinimumIndex, + OUT gctUINT32 * MaximumIndex + ); + +/* Dynamic buffer management. */ +gceSTATUS +gcoINDEX_SetDynamic( + IN gcoINDEX Index, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +gceSTATUS +gcoINDEX_UploadDynamic( + IN gcoINDEX Index, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes + ); + +/******************************************************************************\ +********************************** gco3D Object ********************************* +\******************************************************************************/ + +/* Clear flags. */ +typedef enum _gceCLEAR +{ + gcvCLEAR_COLOR = 0x1, + gcvCLEAR_DEPTH = 0x2, + gcvCLEAR_STENCIL = 0x4, + gcvCLEAR_HZ = 0x8, + gcvCLEAR_HAS_VAA = 0x10, +} +gceCLEAR; + +/* Blending targets. */ +typedef enum _gceBLEND_UNIT +{ + gcvBLEND_SOURCE, + gcvBLEND_TARGET, +} +gceBLEND_UNIT; + +/* Construct a new gco3D object. */ +gceSTATUS +gco3D_Construct( + IN gcoHAL Hal, + OUT gco3D * Engine + ); + +/* Destroy an gco3D object. */ +gceSTATUS +gco3D_Destroy( + IN gco3D Engine + ); + +/* Set 3D API type. */ +gceSTATUS +gco3D_SetAPI( + IN gco3D Engine, + IN gceAPI ApiType + ); + +/* Set render target. */ +gceSTATUS +gco3D_SetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset render target. */ +gceSTATUS +gco3D_UnsetTarget( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set depth buffer. */ +gceSTATUS +gco3D_SetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Unset depth buffer. */ +gceSTATUS +gco3D_UnsetDepth( + IN gco3D Engine, + IN gcoSURF Surface + ); + +/* Set viewport. */ +gceSTATUS +gco3D_SetViewport( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set scissors. */ +gceSTATUS +gco3D_SetScissors( + IN gco3D Engine, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom + ); + +/* Set clear color. */ +gceSTATUS +gco3D_SetClearColor( + IN gco3D Engine, + IN gctUINT8 Red, + IN gctUINT8 Green, + IN gctUINT8 Blue, + IN gctUINT8 Alpha + ); + +/* Set fixed point clear color. */ +gceSTATUS +gco3D_SetClearColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point clear color. */ +gceSTATUS +gco3D_SetClearColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set fixed point clear depth. */ +gceSTATUS +gco3D_SetClearDepthX( + IN gco3D Engine, + IN gctFIXED_POINT Depth + ); + +/* Set floating point clear depth. */ +gceSTATUS +gco3D_SetClearDepthF( + IN gco3D Engine, + IN gctFLOAT Depth + ); + +/* Set clear stencil. */ +gceSTATUS +gco3D_SetClearStencil( + IN gco3D Engine, + IN gctUINT32 Stencil + ); + +/* Clear a Rect sub-surface. */ +gceSTATUS +gco3D_ClearRect( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctPOINTER Memory, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctINT32 Left, + IN gctINT32 Top, + IN gctINT32 Right, + IN gctINT32 Bottom, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + +/* Clear surface. */ +gceSTATUS +gco3D_Clear( + IN gco3D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctUINT32 Width, + IN gctUINT32 Height, + IN gctUINT32 Flags + ); + + +/* Clear tile status. */ +gceSTATUS +gco3D_ClearTileStatus( + IN gco3D Engine, + IN gcsSURF_INFO_PTR Surface, + IN gctUINT32 TileStatusAddress, + IN gctUINT32 Flags + ); + +/* Set shading mode. */ +gceSTATUS +gco3D_SetShading( + IN gco3D Engine, + IN gceSHADING Shading + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_EnableBlending( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set blending function. */ +gceSTATUS +gco3D_SetBlendFunction( + IN gco3D Engine, + IN gceBLEND_UNIT Unit, + IN gceBLEND_FUNCTION FunctionRGB, + IN gceBLEND_FUNCTION FunctionAlpha + ); + +/* Set blending mode. */ +gceSTATUS +gco3D_SetBlendMode( + IN gco3D Engine, + IN gceBLEND_MODE ModeRGB, + IN gceBLEND_MODE ModeAlpha + ); + +/* Set blending color. */ +gceSTATUS +gco3D_SetBlendColor( + IN gco3D Engine, + IN gctUINT Red, + IN gctUINT Green, + IN gctUINT Blue, + IN gctUINT Alpha + ); + +/* Set fixed point blending color. */ +gceSTATUS +gco3D_SetBlendColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +/* Set floating point blending color. */ +gceSTATUS +gco3D_SetBlendColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Set culling mode. */ +gceSTATUS +gco3D_SetCulling( + IN gco3D Engine, + IN gceCULL Mode + ); + +/* Enable point size */ +gceSTATUS +gco3D_SetPointSizeEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set point sprite */ +gceSTATUS +gco3D_SetPointSprite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set fill mode. */ +gceSTATUS +gco3D_SetFill( + IN gco3D Engine, + IN gceFILL Mode + ); + +/* Set depth compare mode. */ +gceSTATUS +gco3D_SetDepthCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Enable depth writing. */ +gceSTATUS +gco3D_EnableDepthWrite( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth mode. */ +gceSTATUS +gco3D_SetDepthMode( + IN gco3D Engine, + IN gceDEPTH_MODE Mode + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeX( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFIXED_POINT Near, + IN gctFIXED_POINT Far + ); + +/* Set depth range. */ +gceSTATUS +gco3D_SetDepthRangeF( + IN gco3D Engine, + IN gceDEPTH_MODE Mode, + IN gctFLOAT Near, + IN gctFLOAT Far + ); + +/* Set last pixel enable */ +gceSTATUS +gco3D_SetLastPixelEnable( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set depth Bias and Scale */ +gceSTATUS +gco3D_SetDepthScaleBiasX( + IN gco3D Engine, + IN gctFIXED_POINT DepthScale, + IN gctFIXED_POINT DepthBias + ); + +gceSTATUS +gco3D_SetDepthScaleBiasF( + IN gco3D Engine, + IN gctFLOAT DepthScale, + IN gctFLOAT DepthBias + ); + +/* Enable or disable dithering. */ +gceSTATUS +gco3D_EnableDither( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set color write enable bits. */ +gceSTATUS +gco3D_SetColorWrite( + IN gco3D Engine, + IN gctUINT8 Enable + ); + +/* Enable or disable early depth. */ +gceSTATUS +gco3D_SetEarlyDepth( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Enable or disable all early depth operations. */ +gceSTATUS +gco3D_SetAllEarlyDepthModes( + IN gco3D Engine, + IN gctBOOL Disable + ); + +/* Enable or disable depth-only mode. */ +gceSTATUS +gco3D_SetDepthOnly( + IN gco3D Engine, + IN gctBOOL Enable + ); + +typedef struct _gcsSTENCIL_INFO * gcsSTENCIL_INFO_PTR; +typedef struct _gcsSTENCIL_INFO +{ + gceSTENCIL_MODE mode; + + gctUINT8 mask; + gctUINT8 writeMask; + + gctUINT8 referenceFront; + + gceCOMPARE compareFront; + gceSTENCIL_OPERATION passFront; + gceSTENCIL_OPERATION failFront; + gceSTENCIL_OPERATION depthFailFront; + + gctUINT8 referenceBack; + gceCOMPARE compareBack; + gceSTENCIL_OPERATION passBack; + gceSTENCIL_OPERATION failBack; + gceSTENCIL_OPERATION depthFailBack; +} +gcsSTENCIL_INFO; + +/* Set stencil mode. */ +gceSTATUS +gco3D_SetStencilMode( + IN gco3D Engine, + IN gceSTENCIL_MODE Mode + ); + +/* Set stencil mask. */ +gceSTATUS +gco3D_SetStencilMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil write mask. */ +gceSTATUS +gco3D_SetStencilWriteMask( + IN gco3D Engine, + IN gctUINT8 Mask + ); + +/* Set stencil reference. */ +gceSTATUS +gco3D_SetStencilReference( + IN gco3D Engine, + IN gctUINT8 Reference, + IN gctBOOL Front + ); + +/* Set stencil compare. */ +gceSTATUS +gco3D_SetStencilCompare( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceCOMPARE Compare + ); + +/* Set stencil operation on pass. */ +gceSTATUS +gco3D_SetStencilPass( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on fail. */ +gceSTATUS +gco3D_SetStencilFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set stencil operation on depth fail. */ +gceSTATUS +gco3D_SetStencilDepthFail( + IN gco3D Engine, + IN gceSTENCIL_WHERE Where, + IN gceSTENCIL_OPERATION Operation + ); + +/* Set all stencil states in one blow. */ +gceSTATUS +gco3D_SetStencilAll( + IN gco3D Engine, + IN gcsSTENCIL_INFO_PTR Info + ); + +typedef struct _gcsALPHA_INFO * gcsALPHA_INFO_PTR; +typedef struct _gcsALPHA_INFO +{ + /* Alpha test states. */ + gctBOOL test; + gceCOMPARE compare; + gctUINT8 reference; + + /* Alpha blending states. */ + gctBOOL blend; + + gceBLEND_FUNCTION srcFuncColor; + gceBLEND_FUNCTION srcFuncAlpha; + gceBLEND_FUNCTION trgFuncColor; + gceBLEND_FUNCTION trgFuncAlpha; + + gceBLEND_MODE modeColor; + gceBLEND_MODE modeAlpha; + + gctUINT32 color; +} +gcsALPHA_INFO; + +/* Enable or disable alpha test. */ +gceSTATUS +gco3D_SetAlphaTest( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set alpha test compare. */ +gceSTATUS +gco3D_SetAlphaCompare( + IN gco3D Engine, + IN gceCOMPARE Compare + ); + +/* Set alpha test reference in unsigned integer. */ +gceSTATUS +gco3D_SetAlphaReference( + IN gco3D Engine, + IN gctUINT8 Reference + ); + +/* Set alpha test reference in fixed point. */ +gceSTATUS +gco3D_SetAlphaReferenceX( + IN gco3D Engine, + IN gctFIXED_POINT Reference + ); + +/* Set alpha test reference in floating point. */ +gceSTATUS +gco3D_SetAlphaReferenceF( + IN gco3D Engine, + IN gctFLOAT Reference + ); + +/* Enable/Disable anti-alias line. */ +gceSTATUS +gco3D_SetAntiAliasLine( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Set texture slot for anti-alias line. */ +gceSTATUS +gco3D_SetAALineTexSlot( + IN gco3D Engine, + IN gctUINT TexSlot + ); + +/* Set anti-alias line width scale. */ +gceSTATUS +gco3D_SetAALineWidth( + IN gco3D Engine, + IN gctFLOAT Width + ); + +/* Draw a number of primitives. */ +gceSTATUS +gco3D_DrawPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT StartVertex, + IN gctSIZE_T PrimitiveCount + ); + +gceSTATUS +gco3D_DrawPrimitivesCount( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT* StartVertex, + IN gctSIZE_T* VertexCount, + IN gctSIZE_T PrimitiveCount + ); + + +/* Draw a number of primitives using offsets. */ +gceSTATUS +gco3D_DrawPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives. */ +gceSTATUS +gco3D_DrawIndexedPrimitives( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT BaseVertex, + IN gctINT StartIndex, + IN gctSIZE_T PrimitiveCount + ); + +/* Draw a number of indexed primitives using offsets. */ +gceSTATUS +gco3D_DrawIndexedPrimitivesOffset( + IN gco3D Engine, + IN gcePRIMITIVE Type, + IN gctINT32 BaseOffset, + IN gctINT32 StartOffset, + IN gctSIZE_T PrimitiveCount + ); + +/* Enable or disable anti-aliasing. */ +gceSTATUS +gco3D_SetAntiAlias( + IN gco3D Engine, + IN gctBOOL Enable + ); + +/* Write data into the command buffer. */ +gceSTATUS +gco3D_WriteBuffer( + IN gco3D Engine, + IN gctCONST_POINTER Data, + IN gctSIZE_T Bytes, + IN gctBOOL Aligned + ); + +/* Send sempahore and stall until sempahore is signalled. */ +gceSTATUS +gco3D_Semaphore( + IN gco3D Engine, + IN gceWHERE From, + IN gceWHERE To, + IN gceHOW How); + +/* Set the subpixels center. */ +gceSTATUS +gco3D_SetCentroids( + IN gco3D Engine, + IN gctUINT32 Index, + IN gctPOINTER Centroids + ); + +gceSTATUS +gco3D_SetLogicOp( + IN gco3D Engine, + IN gctUINT8 Rop + ); + +/* OCL thread walker information. */ +typedef struct _gcsTHREAD_WALKER_INFO * gcsTHREAD_WALKER_INFO_PTR; +typedef struct _gcsTHREAD_WALKER_INFO +{ + gctUINT32 dimensions; + gctUINT32 traverseOrder; + gctUINT32 enableSwathX; + gctUINT32 enableSwathY; + gctUINT32 enableSwathZ; + gctUINT32 swathSizeX; + gctUINT32 swathSizeY; + gctUINT32 swathSizeZ; + gctUINT32 valueOrder; + + gctUINT32 globalSizeX; + gctUINT32 globalOffsetX; + gctUINT32 globalSizeY; + gctUINT32 globalOffsetY; + gctUINT32 globalSizeZ; + gctUINT32 globalOffsetZ; + + gctUINT32 workGroupSizeX; + gctUINT32 workGroupCountX; + gctUINT32 workGroupSizeY; + gctUINT32 workGroupCountY; + gctUINT32 workGroupSizeZ; + gctUINT32 workGroupCountZ; + + gctUINT32 threadAllocation; +} +gcsTHREAD_WALKER_INFO; + +/* Start OCL thread walker. */ +gceSTATUS +gco3D_InvokeThreadWalker( + IN gco3D Engine, + IN gcsTHREAD_WALKER_INFO_PTR Info + ); + +/*----------------------------------------------------------------------------*/ +/*-------------------------- gco3D Fragment Processor ------------------------*/ + +/* Set the fragment processor configuration. */ +gceSTATUS +gco3D_SetFragmentConfiguration( + IN gco3D Engine, + IN gctBOOL ColorFromStream, + IN gctBOOL EnableFog, + IN gctBOOL EnableSmoothPoint, + IN gctUINT32 ClipPlanes + ); + +/* Enable/disable texture stage operation. */ +gceSTATUS +gco3D_EnableTextureStage( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL Enable + ); + +/* Program the channel enable masks for the color texture function. */ +gceSTATUS +gco3D_SetTextureColorMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the channel enable masks for the alpha texture function. */ +gceSTATUS +gco3D_SetTextureAlphaMask( + IN gco3D Engine, + IN gctINT Stage, + IN gctBOOL ColorEnabled, + IN gctBOOL AlphaEnabled + ); + +/* Program the constant fragment color. */ +gceSTATUS +gco3D_SetFragmentColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFragmentColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant fog color. */ +gceSTATUS +gco3D_SetFogColorX( + IN gco3D Engine, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetFogColorF( + IN gco3D Engine, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Program the constant texture color. */ +gceSTATUS +gco3D_SetTetxureColorX( + IN gco3D Engine, + IN gctINT Stage, + IN gctFIXED_POINT Red, + IN gctFIXED_POINT Green, + IN gctFIXED_POINT Blue, + IN gctFIXED_POINT Alpha + ); + +gceSTATUS +gco3D_SetTetxureColorF( + IN gco3D Engine, + IN gctINT Stage, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +/* Configure color texture function. */ +gceSTATUS +gco3D_SetColorTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + +/* Configure alpha texture function. */ +gceSTATUS +gco3D_SetAlphaTextureFunction( + IN gco3D Engine, + IN gctINT Stage, + IN gceTEXTURE_FUNCTION Function, + IN gceTEXTURE_SOURCE Source0, + IN gceTEXTURE_CHANNEL Channel0, + IN gceTEXTURE_SOURCE Source1, + IN gceTEXTURE_CHANNEL Channel1, + IN gceTEXTURE_SOURCE Source2, + IN gceTEXTURE_CHANNEL Channel2, + IN gctINT Scale + ); + +/* Invoke OCL thread walker. */ +gceSTATUS +gcoHARDWARE_InvokeThreadWalker( + IN gcsTHREAD_WALKER_INFO_PTR Info + ); + +/******************************************************************************\ +******************************* gcoTEXTURE Object ******************************* +\******************************************************************************/ + +/* Cube faces. */ +typedef enum _gceTEXTURE_FACE +{ + gcvFACE_NONE, + gcvFACE_POSITIVE_X, + gcvFACE_NEGATIVE_X, + gcvFACE_POSITIVE_Y, + gcvFACE_NEGATIVE_Y, + gcvFACE_POSITIVE_Z, + gcvFACE_NEGATIVE_Z, +} +gceTEXTURE_FACE; + +typedef struct _gcsTEXTURE +{ + /* Addressing modes. */ + gceTEXTURE_ADDRESSING s; + gceTEXTURE_ADDRESSING t; + gceTEXTURE_ADDRESSING r; + + /* Border color. */ + gctUINT8 border[4]; + + /* Filters. */ + gceTEXTURE_FILTER minFilter; + gceTEXTURE_FILTER magFilter; + gceTEXTURE_FILTER mipFilter; + gctUINT anisoFilter; + + /* Level of detail. */ + gctFIXED_POINT lodBias; + gctFIXED_POINT lodMin; + gctFIXED_POINT lodMax; +} +gcsTEXTURE, * gcsTEXTURE_PTR; + +/* Construct a new gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Construct( + IN gcoHAL Hal, + OUT gcoTEXTURE * Texture + ); + +/* Construct a new sized gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_ConstructSized( + IN gcoHAL Hal, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gctUINT MipMapCount, + IN gcePOOL Pool, + OUT gcoTEXTURE * Texture + ); + +/* Destroy an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Destroy( + IN gcoTEXTURE Texture + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_Upload( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadSub( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + IN gctUINT X, + IN gctUINT Y, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctINT Stride, + IN gceSURF_FORMAT Format + ); + +/* Upload compressed data to an gcoTEXTURE object. */ +gceSTATUS +gcoTEXTURE_UploadCompressed( + IN gcoTEXTURE Texture, + IN gceTEXTURE_FACE Face, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Slice, + IN gctCONST_POINTER Memory, + IN gctSIZE_T Bytes + ); + +/* Get gcoSURF object for a mipmap level. */ +gceSTATUS +gcoTEXTURE_GetMipMap( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + OUT gcoSURF * Surface + ); + +/* Get gcoSURF object for a mipmap level and face offset. */ +gceSTATUS +gcoTEXTURE_GetMipMapFace( + IN gcoTEXTURE Texture, + IN gctUINT MipMap, + IN gceTEXTURE_FACE Face, + OUT gcoSURF * Surface, + OUT gctUINT32_PTR Offset + ); + +gceSTATUS +gcoTEXTURE_AddMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gceSURF_FORMAT Format, + IN gctUINT Width, + IN gctUINT Height, + IN gctUINT Depth, + IN gctUINT Faces, + IN gcePOOL Pool, + OUT gcoSURF * Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromClient( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_AddMipMapFromSurface( + IN gcoTEXTURE Texture, + IN gctINT Level, + IN gcoSURF Surface + ); + +gceSTATUS +gcoTEXTURE_SetEndianHint( + IN gcoTEXTURE Texture, + IN gceENDIAN_HINT EndianHint + ); + +gceSTATUS +gcoTEXTURE_Disable( + IN gcoHAL Hal, + IN gctINT Sampler + ); + +gceSTATUS +gcoTEXTURE_Flush( + IN gcoTEXTURE Texture + ); + +gceSTATUS +gcoTEXTURE_QueryCaps( + IN gcoHAL Hal, + OUT gctUINT * MaxWidth, + OUT gctUINT * MaxHeight, + OUT gctUINT * MaxDepth, + OUT gctBOOL * Cubic, + OUT gctBOOL * NonPowerOfTwo, + OUT gctUINT * VertexSamplers, + OUT gctUINT * PixelSamplers + ); + +gceSTATUS +gcoTEXTURE_GetClosestFormat( + IN gcoHAL Hal, + IN gceSURF_FORMAT InFormat, + OUT gceSURF_FORMAT* OutFormat + ); + +gceSTATUS +gcoTEXTURE_RenderIntoMipMap( + IN gcoTEXTURE Texture, + IN gctINT Level + ); + +gceSTATUS +gcoTEXTURE_IsRenderable( + IN gcoTEXTURE Texture, + IN gctUINT Level + ); + +gceSTATUS +gcoTEXTURE_IsComplete( + IN gcoTEXTURE Texture, + IN gctINT MaxLevel + ); + +gceSTATUS +gcoTEXTURE_BindTexture( + IN gcoTEXTURE Texture, + IN gctINT Target, + IN gctINT Sampler, + IN gcsTEXTURE_PTR Info + ); + +/******************************************************************************\ +******************************* gcoSTREAM Object ****************************** +\******************************************************************************/ + +typedef enum _gceVERTEX_FORMAT +{ + gcvVERTEX_BYTE, + gcvVERTEX_UNSIGNED_BYTE, + gcvVERTEX_SHORT, + gcvVERTEX_UNSIGNED_SHORT, + gcvVERTEX_INT, + gcvVERTEX_UNSIGNED_INT, + gcvVERTEX_FIXED, + gcvVERTEX_HALF, + gcvVERTEX_FLOAT, + gcvVERTEX_UNSIGNED_INT_10_10_10_2, + gcvVERTEX_INT_10_10_10_2, +} +gceVERTEX_FORMAT; + +gceSTATUS +gcoSTREAM_Construct( + IN gcoHAL Hal, + OUT gcoSTREAM * Stream + ); + +gceSTATUS +gcoSTREAM_Destroy( + IN gcoSTREAM Stream + ); + +gceSTATUS +gcoSTREAM_Upload( + IN gcoSTREAM Stream, + IN gctCONST_POINTER Buffer, + IN gctUINT32 Offset, + IN gctSIZE_T Bytes, + IN gctBOOL Dynamic + ); + +gceSTATUS +gcoSTREAM_SetStride( + IN gcoSTREAM Stream, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoSTREAM_Lock( + IN gcoSTREAM Stream, + OUT gctPOINTER * Logical, + OUT gctUINT32 * Physical + ); + +gceSTATUS +gcoSTREAM_Unlock( + IN gcoSTREAM Stream + ); + +gceSTATUS +gcoSTREAM_Reserve( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes + ); + +gceSTATUS +gcoSTREAM_Flush( + IN gcoSTREAM Stream + ); + +/* Dynamic buffer API. */ +gceSTATUS +gcoSTREAM_SetDynamic( + IN gcoSTREAM Stream, + IN gctSIZE_T Bytes, + IN gctUINT Buffers + ); + +typedef struct _gcsSTREAM_INFO +{ + gctUINT index; + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT components; + gctSIZE_T size; + gctCONST_POINTER data; + gctUINT stride; +} +gcsSTREAM_INFO, * gcsSTREAM_INFO_PTR; + +gceSTATUS +gcoSTREAM_UploadDynamic( + IN gcoSTREAM Stream, + IN gctUINT VertexCount, + IN gctUINT InfoCount, + IN gcsSTREAM_INFO_PTR Info, + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoSTREAM_CPUCacheOperation( + IN gcoSTREAM Stream, + IN gceCACHEOPERATION Operation + ); + +/******************************************************************************\ +******************************** gcoVERTEX Object ****************************** +\******************************************************************************/ + +typedef struct _gcsVERTEX_ATTRIBUTES +{ + gceVERTEX_FORMAT format; + gctBOOL normalized; + gctUINT32 components; + gctSIZE_T size; + gctUINT32 stream; + gctUINT32 offset; + gctUINT32 stride; +} +gcsVERTEX_ATTRIBUTES; + +gceSTATUS +gcoVERTEX_Construct( + IN gcoHAL Hal, + OUT gcoVERTEX * Vertex + ); + +gceSTATUS +gcoVERTEX_Destroy( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_Reset( + IN gcoVERTEX Vertex + ); + +gceSTATUS +gcoVERTEX_EnableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index, + IN gceVERTEX_FORMAT Format, + IN gctBOOL Normalized, + IN gctUINT32 Components, + IN gcoSTREAM Stream, + IN gctUINT32 Offset, + IN gctUINT32 Stride + ); + +gceSTATUS +gcoVERTEX_DisableAttribute( + IN gcoVERTEX Vertex, + IN gctUINT32 Index + ); + +gceSTATUS +gcoVERTEX_Bind( + IN gcoVERTEX Vertex + ); + +/******************************************************************************* +***** gcoVERTEXARRAY Object ***************************************************/ + +typedef struct _gcsVERTEXARRAY +{ + /* Enabled. */ + gctBOOL enable; + + /* Number of components. */ + gctINT size; + + /* Attribute format. */ + gceVERTEX_FORMAT format; + + /* Flag whether the attribute is normalized or not. */ + gctBOOL normalized; + + /* Stride of the component. */ + gctUINT stride; + + /* Pointer to the attribute data. */ + gctCONST_POINTER pointer; + + /* Stream object owning the attribute data. */ + gcoSTREAM stream; + + /* Generic values for attribute. */ + gctFLOAT genericValue[4]; + + /* Vertex shader linkage. */ + gctUINT linkage; +} +gcsVERTEXARRAY, +* gcsVERTEXARRAY_PTR; + +gceSTATUS +gcoVERTEXARRAY_Construct( + IN gcoHAL Hal, + OUT gcoVERTEXARRAY * Vertex + ); + +gceSTATUS +gcoVERTEXARRAY_Destroy( + IN gcoVERTEXARRAY Vertex + ); + +gceSTATUS +gcoVERTEXARRAY_Bind( + IN gcoVERTEXARRAY Vertex, + IN gctUINT32 EnableBits, + IN gcsVERTEXARRAY_PTR VertexArray, + IN gctUINT First, + IN gctSIZE_T Count, + IN gceINDEX_TYPE IndexType, + IN gcoINDEX IndexObject, + IN gctPOINTER IndexMemory, + IN OUT gcePRIMITIVE * PrimitiveType, + IN OUT gctUINT * PrimitiveCount + ); + +/******************************************************************************* +***** Composition *************************************************************/ + +typedef enum _gceCOMPOSITION +{ + gcvCOMPOSE_CLEAR = 1, + gcvCOMPOSE_BLUR, + gcvCOMPOSE_DIM, + gcvCOMPOSE_LAYER +} +gceCOMPOSITION; + +typedef struct _gcsCOMPOSITION * gcsCOMPOSITION_PTR; +typedef struct _gcsCOMPOSITION +{ + /* Structure size. */ + gctUINT structSize; + + /* Composition operation. */ + gceCOMPOSITION operation; + + /* Layer to be composed. */ + gcoSURF layer; + + /* Source and target coordinates. */ + gcsRECT srcRect; + gcsRECT trgRect; + + /* Target rectangle */ + gcsPOINT v0; + gcsPOINT v1; + gcsPOINT v2; + + /* Blending parameters. */ + gctBOOL enableBlending; + gctBOOL premultiplied; + gctUINT8 alphaValue; + + /* Clear color. */ + gctFLOAT r; + gctFLOAT g; + gctFLOAT b; + gctFLOAT a; +} +gcsCOMPOSITION; + +gceSTATUS +gco3D_ProbeComposition( + gctBOOL ResetIfEmpty + ); + +gceSTATUS +gco3D_CompositionBegin( + void + ); + +gceSTATUS +gco3D_ComposeLayer( + IN gcsCOMPOSITION_PTR Layer + ); + +gceSTATUS +gco3D_CompositionSignals( + IN gctHANDLE Process, + IN gctSIGNAL Signal1, + IN gctSIGNAL Signal2 + ); + +gceSTATUS +gco3D_CompositionEnd( + IN gcoSURF Target, + IN gctBOOL Synchronous + ); + +/* Frame Database */ +gceSTATUS +gcoHAL_AddFrameDB( + void + ); + +gceSTATUS +gcoHAL_DumpFrameDB( + gctCONST_STRING Filename OPTIONAL + ); + +gceSTATUS +gcoHAL_GetSharedInfo( + IN gctUINT32 Pid, + IN gctUINT32 DataId, + OUT gctUINT8_PTR Data, + IN gctSIZE_T Bytes, + IN gcuVIDMEM_NODE_PTR Node, + OUT gctUINT8_PTR NodeData, + IN gceVIDMEM_NODE_SHARED_INFO_TYPE SharedInfoType + ); + +gceSTATUS +gcoHAL_SetSharedInfo( + IN gctUINT32 DataId, + IN gctUINT8_PTR Data, + IN gctSIZE_T Bytes, + IN gcuVIDMEM_NODE_PTR Node, + IN gctUINT8_PTR NodeData, + IN gceVIDMEM_NODE_SHARED_INFO_TYPE SharedInfoType + ); + +#ifdef __cplusplus +} +#endif + +#endif /* VIVANTE_NO_3D */ +#endif /* __gc_hal_engine_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine_vg.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine_vg.h new file mode 100644 index 0000000..571e03e --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_engine_vg.h @@ -0,0 +1,908 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + + + +#ifndef __gc_hal_engine_vg_h_ +#define __gc_hal_engine_vg_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gc_hal_types.h" + +/******************************************************************************\ +******************************** VG Enumerations ******************************* +\******************************************************************************/ + +/** +** @ingroup gcoVG +** +** @brief Tiling mode for painting and imagig. +** +** This enumeration defines the tiling modes supported by the HAL. This is +** in fact a one-to-one mapping of the OpenVG 1.1 tile modes. +*/ +typedef enum _gceTILE_MODE +{ + gcvTILE_FILL, + gcvTILE_PAD, + gcvTILE_REPEAT, + gcvTILE_REFLECT +} +gceTILE_MODE; + +/******************************************************************************/ +/** @ingroup gcoVG +** +** @brief The different paint modes. +** +** This enumeration lists the available paint modes. +*/ +typedef enum _gcePAINT_TYPE +{ + /** Solid color. */ + gcvPAINT_MODE_SOLID, + + /** Linear gradient. */ + gcvPAINT_MODE_LINEAR, + + /** Radial gradient. */ + gcvPAINT_MODE_RADIAL, + + /** Pattern. */ + gcvPAINT_MODE_PATTERN, + + /** Mode count. */ + gcvPAINT_MODE_COUNT +} +gcePAINT_TYPE; + +/** +** @ingroup gcoVG +** +** @brief Types of path data supported by HAL. +** +** This enumeration defines the types of path data supported by the HAL. +** This is in fact a one-to-one mapping of the OpenVG 1.1 path types. +*/ +typedef enum _gcePATHTYPE +{ + gcePATHTYPE_UNKNOWN = -1, + gcePATHTYPE_INT8, + gcePATHTYPE_INT16, + gcePATHTYPE_INT32, + gcePATHTYPE_FLOAT +} +gcePATHTYPE; + +/** +** @ingroup gcoVG +** +** @brief Supported path segment commands. +** +** This enumeration defines the path segment commands supported by the HAL. +*/ +typedef enum _gceVGCMD +{ + gcvVGCMD_END, /* 0: GCCMD_TS_OPCODE_END */ + gcvVGCMD_CLOSE, /* 1: GCCMD_TS_OPCODE_CLOSE */ + gcvVGCMD_MOVE, /* 2: GCCMD_TS_OPCODE_MOVE */ + gcvVGCMD_MOVE_REL, /* 3: GCCMD_TS_OPCODE_MOVE_REL */ + gcvVGCMD_LINE, /* 4: GCCMD_TS_OPCODE_LINE */ + gcvVGCMD_LINE_REL, /* 5: GCCMD_TS_OPCODE_LINE_REL */ + gcvVGCMD_QUAD, /* 6: GCCMD_TS_OPCODE_QUADRATIC */ + gcvVGCMD_QUAD_REL, /* 7: GCCMD_TS_OPCODE_QUADRATIC_REL */ + gcvVGCMD_CUBIC, /* 8: GCCMD_TS_OPCODE_CUBIC */ + gcvVGCMD_CUBIC_REL, /* 9: GCCMD_TS_OPCODE_CUBIC_REL */ + gcvVGCMD_BREAK, /* 10: GCCMD_TS_OPCODE_BREAK */ + gcvVGCMD_HLINE, /* 11: ******* R E S E R V E D *******/ + gcvVGCMD_HLINE_REL, /* 12: ******* R E S E R V E D *******/ + gcvVGCMD_VLINE, /* 13: ******* R E S E R V E D *******/ + gcvVGCMD_VLINE_REL, /* 14: ******* R E S E R V E D *******/ + gcvVGCMD_SQUAD, /* 15: ******* R E S E R V E D *******/ + gcvVGCMD_SQUAD_REL, /* 16: ******* R E S E R V E D *******/ + gcvVGCMD_SCUBIC, /* 17: ******* R E S E R V E D *******/ + gcvVGCMD_SCUBIC_REL, /* 18: ******* R E S E R V E D *******/ + gcvVGCMD_SCCWARC, /* 19: ******* R E S E R V E D *******/ + gcvVGCMD_SCCWARC_REL, /* 20: ******* R E S E R V E D *******/ + gcvVGCMD_SCWARC, /* 21: ******* R E S E R V E D *******/ + gcvVGCMD_SCWARC_REL, /* 22: ******* R E S E R V E D *******/ + gcvVGCMD_LCCWARC, /* 23: ******* R E S E R V E D *******/ + gcvVGCMD_LCCWARC_REL, /* 24: ******* R E S E R V E D *******/ + gcvVGCMD_LCWARC, /* 25: ******* R E S E R V E D *******/ + gcvVGCMD_LCWARC_REL, /* 26: ******* R E S E R V E D *******/ + + /* The width of the command recognized by the hardware on bits. */ + gcvVGCMD_WIDTH = 5, + + /* Hardware command mask. */ + gcvVGCMD_MASK = (1 << gcvVGCMD_WIDTH) - 1, + + /* Command modifiers. */ + gcvVGCMD_H_MOD = 1 << gcvVGCMD_WIDTH, /* = 32 */ + gcvVGCMD_V_MOD = 2 << gcvVGCMD_WIDTH, /* = 64 */ + gcvVGCMD_S_MOD = 3 << gcvVGCMD_WIDTH, /* = 96 */ + gcvVGCMD_ARC_MOD = 4 << gcvVGCMD_WIDTH, /* = 128 */ + + /* Emulated LINE commands. */ + gcvVGCMD_HLINE_EMUL = gcvVGCMD_H_MOD | gcvVGCMD_LINE, /* = 36 */ + gcvVGCMD_HLINE_EMUL_REL = gcvVGCMD_H_MOD | gcvVGCMD_LINE_REL, /* = 37 */ + gcvVGCMD_VLINE_EMUL = gcvVGCMD_V_MOD | gcvVGCMD_LINE, /* = 68 */ + gcvVGCMD_VLINE_EMUL_REL = gcvVGCMD_V_MOD | gcvVGCMD_LINE_REL, /* = 69 */ + + /* Emulated SMOOTH commands. */ + gcvVGCMD_SQUAD_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD, /* = 102 */ + gcvVGCMD_SQUAD_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_QUAD_REL, /* = 103 */ + gcvVGCMD_SCUBIC_EMUL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC, /* = 104 */ + gcvVGCMD_SCUBIC_EMUL_REL = gcvVGCMD_S_MOD | gcvVGCMD_CUBIC_REL, /* = 105 */ + + /* Emulation ARC commands. */ + gcvVGCMD_ARC_LINE = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE, /* = 132 */ + gcvVGCMD_ARC_LINE_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_LINE_REL, /* = 133 */ + gcvVGCMD_ARC_QUAD = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD, /* = 134 */ + gcvVGCMD_ARC_QUAD_REL = gcvVGCMD_ARC_MOD | gcvVGCMD_QUAD_REL /* = 135 */ +} +gceVGCMD; +typedef enum _gceVGCMD * gceVGCMD_PTR; + +/** +** @ingroup gcoVG +** +** @brief Blending modes supported by the HAL. +** +** This enumeration defines the blending modes supported by the HAL. This is +** in fact a one-to-one mapping of the OpenVG 1.1 blending modes. +*/ +typedef enum _gceVG_BLEND +{ + gcvVG_BLEND_SRC, + gcvVG_BLEND_SRC_OVER, + gcvVG_BLEND_DST_OVER, + gcvVG_BLEND_SRC_IN, + gcvVG_BLEND_DST_IN, + gcvVG_BLEND_MULTIPLY, + gcvVG_BLEND_SCREEN, + gcvVG_BLEND_DARKEN, + gcvVG_BLEND_LIGHTEN, + gcvVG_BLEND_ADDITIVE, + gcvVG_BLEND_SUBTRACT, + gcvVG_BLEND_FILTER +} +gceVG_BLEND; + +/** +** @ingroup gcoVG +** +** @brief Image modes supported by the HAL. +** +** This enumeration defines the image modes supported by the HAL. This is +** in fact a one-to-one mapping of the OpenVG 1.1 image modes with the addition +** of NO IMAGE. +*/ +typedef enum _gceVG_IMAGE +{ + gcvVG_IMAGE_NONE, + gcvVG_IMAGE_NORMAL, + gcvVG_IMAGE_MULTIPLY, + gcvVG_IMAGE_STENCIL, + gcvVG_IMAGE_FILTER +} +gceVG_IMAGE; + +/** +** @ingroup gcoVG +** +** @brief Filter mode patterns and imaging. +** +** This enumeration defines the filter modes supported by the HAL. +*/ +typedef enum _gceIMAGE_FILTER +{ + gcvFILTER_POINT, + gcvFILTER_LINEAR, + gcvFILTER_BI_LINEAR +} +gceIMAGE_FILTER; + +/** +** @ingroup gcoVG +** +** @brief Primitive modes supported by the HAL. +** +** This enumeration defines the primitive modes supported by the HAL. +*/ +typedef enum _gceVG_PRIMITIVE +{ + gcvVG_SCANLINE, + gcvVG_RECTANGLE, + gcvVG_TESSELLATED, + gcvVG_TESSELLATED_TILED +} +gceVG_PRIMITIVE; + +/** +** @ingroup gcoVG +** +** @brief Rendering quality modes supported by the HAL. +** +** This enumeration defines the rendering quality modes supported by the HAL. +*/ +typedef enum _gceRENDER_QUALITY +{ + gcvVG_NONANTIALIASED, + gcvVG_2X2_MSAA, + gcvVG_2X4_MSAA, + gcvVG_4X4_MSAA +} +gceRENDER_QUALITY; + +/** +** @ingroup gcoVG +** +** @brief Fill rules supported by the HAL. +** +** This enumeration defines the fill rules supported by the HAL. +*/ +typedef enum _gceFILL_RULE +{ + gcvVG_EVEN_ODD, + gcvVG_NON_ZERO +} +gceFILL_RULE; + +/** +** @ingroup gcoVG +** +** @brief Cap styles supported by the HAL. +** +** This enumeration defines the cap styles supported by the HAL. +*/ +typedef enum _gceCAP_STYLE +{ + gcvCAP_BUTT, + gcvCAP_ROUND, + gcvCAP_SQUARE +} +gceCAP_STYLE; + +/** +** @ingroup gcoVG +** +** @brief Join styles supported by the HAL. +** +** This enumeration defines the join styles supported by the HAL. +*/ +typedef enum _gceJOIN_STYLE +{ + gcvJOIN_MITER, + gcvJOIN_ROUND, + gcvJOIN_BEVEL +} +gceJOIN_STYLE; + +/** +** @ingroup gcoVG +** +** @brief Channel mask values. +** +** This enumeration defines the values for channel mask used in image +** filtering. +*/ + +/* Base values for channel mask definitions. */ +#define gcvCHANNEL_X (0) +#define gcvCHANNEL_R (1 << 0) +#define gcvCHANNEL_G (1 << 1) +#define gcvCHANNEL_B (1 << 2) +#define gcvCHANNEL_A (1 << 3) + +typedef enum _gceCHANNEL +{ + gcvCHANNEL_XXXX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X), + gcvCHANNEL_XXXA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A), + gcvCHANNEL_XXBX = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X), + gcvCHANNEL_XXBA = (gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A), + + gcvCHANNEL_XGXX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X), + gcvCHANNEL_XGXA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A), + gcvCHANNEL_XGBX = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X), + gcvCHANNEL_XGBA = (gcvCHANNEL_X | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A), + + gcvCHANNEL_RXXX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_X), + gcvCHANNEL_RXXA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_X | gcvCHANNEL_A), + gcvCHANNEL_RXBX = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_X), + gcvCHANNEL_RXBA = (gcvCHANNEL_R | gcvCHANNEL_X | gcvCHANNEL_B | gcvCHANNEL_A), + + gcvCHANNEL_RGXX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_X), + gcvCHANNEL_RGXA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_X | gcvCHANNEL_A), + gcvCHANNEL_RGBX = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_X), + gcvCHANNEL_RGBA = (gcvCHANNEL_R | gcvCHANNEL_G | gcvCHANNEL_B | gcvCHANNEL_A), +} +gceCHANNEL; + +/******************************************************************************\ +******************************** VG Structures ******************************* +\******************************************************************************/ + +/** +** @ingroup gcoVG +** +** @brief Definition of the color ramp used by the gradient paints. +** +** The gcsCOLOR_RAMP structure defines the layout of one single color inside +** a color ramp which is used by gradient paints. +*/ +typedef struct _gcsCOLOR_RAMP +{ + /** Value for the color stop. */ + gctFLOAT stop; + + /** Red color channel value for the color stop. */ + gctFLOAT red; + + /** Green color channel value for the color stop. */ + gctFLOAT green; + + /** Blue color channel value for the color stop. */ + gctFLOAT blue; + + /** Alpha color channel value for the color stop. */ + gctFLOAT alpha; +} +gcsCOLOR_RAMP, * gcsCOLOR_RAMP_PTR; + +/** +** @ingroup gcoVG +** +** @brief Definition of the color ramp used by the gradient paints in fixed form. +** +** The gcsCOLOR_RAMP structure defines the layout of one single color inside +** a color ramp which is used by gradient paints. +*/ +typedef struct _gcsFIXED_COLOR_RAMP +{ + /** Value for the color stop. */ + gctFIXED_POINT stop; + + /** Red color channel value for the color stop. */ + gctFIXED_POINT red; + + /** Green color channel value for the color stop. */ + gctFIXED_POINT green; + + /** Blue color channel value for the color stop. */ + gctFIXED_POINT blue; + + /** Alpha color channel value for the color stop. */ + gctFIXED_POINT alpha; +} +gcsFIXED_COLOR_RAMP, * gcsFIXED_COLOR_RAMP_PTR; + + +/** +** @ingroup gcoVG +** +** @brief Rectangle structure used by the gcoVG object. +** +** This structure defines the layout of a rectangle. Make sure width and +** height are larger than 0. +*/ +typedef struct _gcsVG_RECT * gcsVG_RECT_PTR; +typedef struct _gcsVG_RECT +{ + /** Left location of the rectangle. */ + gctINT x; + + /** Top location of the rectangle. */ + gctINT y; + + /** Width of the rectangle. */ + gctINT width; + + /** Height of the rectangle. */ + gctINT height; +} +gcsVG_RECT; + +/** +** @ingroup gcoVG +** +** @brief Path command buffer attribute structure. +** +** The gcsPATH_BUFFER_INFO structure contains the specifics about +** the layout of the path data command buffer. +*/ +typedef struct _gcsPATH_BUFFER_INFO * gcsPATH_BUFFER_INFO_PTR; +typedef struct _gcsPATH_BUFFER_INFO +{ + gctUINT reservedForHead; + gctUINT reservedForTail; +} +gcsPATH_BUFFER_INFO; + +/** +** @ingroup gcoVG +** +** @brief Definition of the path data container structure. +** +** The gcsPATH structure defines the layout of the path data container. +*/ +typedef struct _gcsPATH_DATA * gcsPATH_DATA_PTR; +typedef struct _gcsPATH_DATA +{ + /* Data container in command buffer format. */ + gcsCMDBUFFER data; + + /* Path data type. */ + gcePATHTYPE dataType; +} +gcsPATH_DATA; + + +/******************************************************************************\ +********************************* gcoHAL Object ******************************** +\******************************************************************************/ + +/* Query path data storage attributes. */ +gceSTATUS +gcoHAL_QueryPathStorage( + IN gcoHAL Hal, + OUT gcsPATH_BUFFER_INFO_PTR Information + ); + +/* Associate a completion signal with the command buffer. */ +gceSTATUS +gcoHAL_AssociateCompletion( + IN gcoHAL Hal, + IN gcsPATH_DATA_PTR PathData + ); + +/* Release the current command buffer completion signal. */ +gceSTATUS +gcoHAL_DeassociateCompletion( + IN gcoHAL Hal, + IN gcsPATH_DATA_PTR PathData + ); + +/* Verify whether the command buffer is still in use. */ +gceSTATUS +gcoHAL_CheckCompletion( + IN gcoHAL Hal, + IN gcsPATH_DATA_PTR PathData + ); + +/* Wait until the command buffer is no longer in use. */ +gceSTATUS +gcoHAL_WaitCompletion( + IN gcoHAL Hal, + IN gcsPATH_DATA_PTR PathData + ); + +/* Flush the pixel cache. */ +gceSTATUS +gcoHAL_Flush( + IN gcoHAL Hal + ); + +/* Split a harwdare address into pool and offset. */ +gceSTATUS +gcoHAL_SplitAddress( + IN gcoHAL Hal, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ); + +/* Combine pool and offset into a harwdare address. */ +gceSTATUS +gcoHAL_CombineAddress( + IN gcoHAL Hal, + IN gcePOOL Pool, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ); + +/* Schedule to free linear video memory allocated. */ +gceSTATUS +gcoHAL_ScheduleVideoMemory( + IN gcoHAL Hal, + IN gcuVIDMEM_NODE_PTR Node + ); + +/* Free linear video memory allocated with gcoHAL_AllocateLinearVideoMemory. */ +gceSTATUS +gcoHAL_FreeVideoMemory( + IN gcoHAL Hal, + IN gcuVIDMEM_NODE_PTR Node + ); + +/* Query command buffer attributes. */ +gceSTATUS +gcoHAL_QueryCommandBuffer( + IN gcoHAL Hal, + OUT gcsCOMMAND_BUFFER_INFO_PTR Information + ); +/* Allocate and lock linear video memory. */ +gceSTATUS +gcoHAL_AllocateLinearVideoMemory( + IN gcoHAL Hal, + IN gctUINT Size, + IN gctUINT Alignment, + IN gcePOOL Pool, + OUT gcuVIDMEM_NODE_PTR * Node, + OUT gctUINT32 * Address, + OUT gctPOINTER * Memory + ); + +/* Align the specified size accordingly to the hardware requirements. */ +gceSTATUS +gcoHAL_GetAlignedSurfaceSize( + IN gcoHAL Hal, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height + ); + +gceSTATUS +gcoHAL_ReserveTask( + IN gcoHAL Hal, + IN gceBLOCK Block, + IN gctUINT TaskCount, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ); +/******************************************************************************\ +********************************** gcoVG Object ******************************** +\******************************************************************************/ + +/** @defgroup gcoVG gcoVG +** +** The gcoVG object abstracts the VG hardware pipe. +*/ + +gctBOOL +gcoVG_IsMaskSupported( + IN gceSURF_FORMAT Format + ); + +gctBOOL +gcoVG_IsTargetSupported( + IN gceSURF_FORMAT Format + ); + +gctBOOL +gcoVG_IsImageSupported( + IN gceSURF_FORMAT Format + ); + +gctUINT8 gcoVG_PackColorComponent( + gctFLOAT Value + ); + +gceSTATUS +gcoVG_Construct( + IN gcoHAL Hal, + OUT gcoVG * Vg + ); + +gceSTATUS +gcoVG_Destroy( + IN gcoVG Vg + ); + +gceSTATUS +gcoVG_SetTarget( + IN gcoVG Vg, + IN gcoSURF Target + ); + +gceSTATUS +gcoVG_UnsetTarget( + IN gcoVG Vg, + IN gcoSURF Surface + ); + +gceSTATUS +gcoVG_SetUserToSurface( + IN gcoVG Vg, + IN gctFLOAT UserToSurface[9] + ); + +gceSTATUS +gcoVG_SetSurfaceToImage( + IN gcoVG Vg, + IN gctFLOAT SurfaceToImage[9] + ); + +gceSTATUS +gcoVG_EnableMask( + IN gcoVG Vg, + IN gctBOOL Enable + ); + +gceSTATUS +gcoVG_SetMask( + IN gcoVG Vg, + IN gcoSURF Mask + ); + +gceSTATUS +gcoVG_UnsetMask( + IN gcoVG Vg, + IN gcoSURF Surface + ); + +gceSTATUS +gcoVG_FlushMask( + IN gcoVG Vg + ); + +gceSTATUS +gcoVG_EnableScissor( + IN gcoVG Vg, + IN gctBOOL Enable + ); + +gceSTATUS +gcoVG_SetScissor( + IN gcoVG Vg, + IN gctSIZE_T RectangleCount, + IN gcsVG_RECT_PTR Rectangles + ); + +gceSTATUS +gcoVG_EnableColorTransform( + IN gcoVG Vg, + IN gctBOOL Enable + ); + +gceSTATUS +gcoVG_SetColorTransform( + IN gcoVG Vg, + IN gctFLOAT ColorTransform[8] + ); + +gceSTATUS +gcoVG_SetTileFillColor( + IN gcoVG Vg, + IN gctFLOAT Red, + IN gctFLOAT Green, + IN gctFLOAT Blue, + IN gctFLOAT Alpha + ); + +gceSTATUS +gcoVG_SetSolidPaint( + IN gcoVG Vg, + IN gctUINT8 Red, + IN gctUINT8 Green, + IN gctUINT8 Blue, + IN gctUINT8 Alpha + ); + +gceSTATUS +gcoVG_SetLinearPaint( + IN gcoVG Vg, + IN gctFLOAT Constant, + IN gctFLOAT StepX, + IN gctFLOAT StepY + ); + +gceSTATUS +gcoVG_SetRadialPaint( + IN gcoVG Vg, + IN gctFLOAT LinConstant, + IN gctFLOAT LinStepX, + IN gctFLOAT LinStepY, + IN gctFLOAT RadConstant, + IN gctFLOAT RadStepX, + IN gctFLOAT RadStepY, + IN gctFLOAT RadStepXX, + IN gctFLOAT RadStepYY, + IN gctFLOAT RadStepXY + ); + +gceSTATUS +gcoVG_SetPatternPaint( + IN gcoVG Vg, + IN gctFLOAT UConstant, + IN gctFLOAT UStepX, + IN gctFLOAT UStepY, + IN gctFLOAT VConstant, + IN gctFLOAT VStepX, + IN gctFLOAT VStepY, + IN gctBOOL Linear + ); + +gceSTATUS +gcoVG_SetColorRamp( + IN gcoVG Vg, + IN gcoSURF ColorRamp, + IN gceTILE_MODE ColorRampSpreadMode + ); + +gceSTATUS +gcoVG_SetPattern( + IN gcoVG Vg, + IN gcoSURF Pattern, + IN gceTILE_MODE TileMode, + IN gceIMAGE_FILTER Filter + ); + +gceSTATUS +gcoVG_SetImageMode( + IN gcoVG Vg, + IN gceVG_IMAGE Mode + ); + +gceSTATUS +gcoVG_SetBlendMode( + IN gcoVG Vg, + IN gceVG_BLEND Mode + ); + +gceSTATUS +gcoVG_SetRenderingQuality( + IN gcoVG Vg, + IN gceRENDER_QUALITY Quality + ); + +gceSTATUS +gcoVG_SetFillRule( + IN gcoVG Vg, + IN gceFILL_RULE FillRule + ); + +gceSTATUS +gcoVG_FinalizePath( + IN gcoVG Vg, + IN gcsPATH_DATA_PTR PathData + ); + +gceSTATUS +gcoVG_Clear( + IN gcoVG Vg, + IN gctINT X, + IN gctINT Y, + IN gctINT Width, + IN gctINT Height + ); + +gceSTATUS +gcoVG_DrawPath( + IN gcoVG Vg, + IN gcsPATH_DATA_PTR PathData, + IN gctFLOAT Scale, + IN gctFLOAT Bias, + IN gctBOOL SoftwareTesselation + ); + +gceSTATUS +gcoVG_DrawImage( + IN gcoVG Vg, + IN gcoSURF Source, + IN gcsPOINT_PTR SourceOrigin, + IN gcsPOINT_PTR TargetOrigin, + IN gcsSIZE_PTR SourceSize, + IN gctINT SourceX, + IN gctINT SourceY, + IN gctINT TargetX, + IN gctINT TargetY, + IN gctINT Width, + IN gctINT Height, + IN gctBOOL Mask + ); + +gceSTATUS +gcoVG_TesselateImage( + IN gcoVG Vg, + IN gcoSURF Image, + IN gcsVG_RECT_PTR Rectangle, + IN gceIMAGE_FILTER Filter, + IN gctBOOL Mask, + IN gctBOOL SoftwareTesselation + ); + +gceSTATUS +gcoVG_Blit( + IN gcoVG Vg, + IN gcoSURF Source, + IN gcoSURF Target, + IN gcsVG_RECT_PTR SrcRect, + IN gcsVG_RECT_PTR TrgRect, + IN gceIMAGE_FILTER Filter, + IN gceVG_BLEND Mode + ); + +gceSTATUS +gcoVG_ColorMatrix( + IN gcoVG Vg, + IN gcoSURF Source, + IN gcoSURF Target, + IN const gctFLOAT * Matrix, + IN gceCHANNEL ColorChannels, + IN gctBOOL FilterLinear, + IN gctBOOL FilterPremultiplied, + IN gcsPOINT_PTR SourceOrigin, + IN gcsPOINT_PTR TargetOrigin, + IN gctINT Width, + IN gctINT Height + ); + +gceSTATUS +gcoVG_SeparableConvolve( + IN gcoVG Vg, + IN gcoSURF Source, + IN gcoSURF Target, + IN gctINT KernelWidth, + IN gctINT KernelHeight, + IN gctINT ShiftX, + IN gctINT ShiftY, + IN const gctINT16 * KernelX, + IN const gctINT16 * KernelY, + IN gctFLOAT Scale, + IN gctFLOAT Bias, + IN gceTILE_MODE TilingMode, + IN gctFLOAT_PTR FillColor, + IN gceCHANNEL ColorChannels, + IN gctBOOL FilterLinear, + IN gctBOOL FilterPremultiplied, + IN gcsPOINT_PTR SourceOrigin, + IN gcsPOINT_PTR TargetOrigin, + IN gcsSIZE_PTR SourceSize, + IN gctINT Width, + IN gctINT Height + ); + +gceSTATUS +gcoVG_GaussianBlur( + IN gcoVG Vg, + IN gcoSURF Source, + IN gcoSURF Target, + IN gctFLOAT StdDeviationX, + IN gctFLOAT StdDeviationY, + IN gceTILE_MODE TilingMode, + IN gctFLOAT_PTR FillColor, + IN gceCHANNEL ColorChannels, + IN gctBOOL FilterLinear, + IN gctBOOL FilterPremultiplied, + IN gcsPOINT_PTR SourceOrigin, + IN gcsPOINT_PTR TargetOrigin, + IN gcsSIZE_PTR SourceSize, + IN gctINT Width, + IN gctINT Height + ); + +gceSTATUS +gcoVG_EnableDither( + IN gcoVG Vg, + IN gctBOOL Enable + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_vg_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_enum.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_enum.h new file mode 100644 index 0000000..7d67828 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_enum.h @@ -0,0 +1,823 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_enum_h_ +#define __gc_hal_enum_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Chip models. */ +typedef enum _gceCHIPMODEL +{ + gcv300 = 0x0300, + gcv320 = 0x0320, + gcv350 = 0x0350, + gcv355 = 0x0355, + gcv400 = 0x0400, + gcv410 = 0x0410, + gcv420 = 0x0420, + gcv450 = 0x0450, + gcv500 = 0x0500, + gcv530 = 0x0530, + gcv600 = 0x0600, + gcv700 = 0x0700, + gcv800 = 0x0800, + gcv860 = 0x0860, + gcv880 = 0x0880, + gcv1000 = 0x1000, + gcv2000 = 0x2000, + gcv2100 = 0x2100, + gcv4000 = 0x4000, +} +gceCHIPMODEL; + +/* Chip features. */ +typedef enum _gceFEATURE +{ + gcvFEATURE_PIPE_2D = 0, + gcvFEATURE_PIPE_3D, + gcvFEATURE_PIPE_VG, + gcvFEATURE_DC, + gcvFEATURE_HIGH_DYNAMIC_RANGE, + gcvFEATURE_MODULE_CG, + gcvFEATURE_MIN_AREA, + gcvFEATURE_BUFFER_INTERLEAVING, + gcvFEATURE_BYTE_WRITE_2D, + gcvFEATURE_ENDIANNESS_CONFIG, + gcvFEATURE_DUAL_RETURN_BUS, + gcvFEATURE_DEBUG_MODE, + gcvFEATURE_YUY2_RENDER_TARGET, + gcvFEATURE_FRAGMENT_PROCESSOR, + gcvFEATURE_2DPE20, + gcvFEATURE_FAST_CLEAR, + gcvFEATURE_YUV420_TILER, + gcvFEATURE_YUY2_AVERAGING, + gcvFEATURE_FLIP_Y, + gcvFEATURE_EARLY_Z, + gcvFEATURE_Z_COMPRESSION, + gcvFEATURE_MSAA, + gcvFEATURE_SPECIAL_ANTI_ALIASING, + gcvFEATURE_SPECIAL_MSAA_LOD, + gcvFEATURE_422_TEXTURE_COMPRESSION, + gcvFEATURE_DXT_TEXTURE_COMPRESSION, + gcvFEATURE_ETC1_TEXTURE_COMPRESSION, + gcvFEATURE_CORRECT_TEXTURE_CONVERTER, + gcvFEATURE_TEXTURE_8K, + gcvFEATURE_SCALER, + gcvFEATURE_YUV420_SCALER, + gcvFEATURE_SHADER_HAS_W, + gcvFEATURE_SHADER_HAS_SIGN, + gcvFEATURE_SHADER_HAS_FLOOR, + gcvFEATURE_SHADER_HAS_CEIL, + gcvFEATURE_SHADER_HAS_SQRT, + gcvFEATURE_SHADER_HAS_TRIG, + gcvFEATURE_VAA, + gcvFEATURE_HZ, + gcvFEATURE_CORRECT_STENCIL, + gcvFEATURE_VG20, + gcvFEATURE_VG_FILTER, + gcvFEATURE_VG21, + gcvFEATURE_VG_DOUBLE_BUFFER, + gcvFEATURE_MC20, + gcvFEATURE_SUPER_TILED, + gcvFEATURE_2D_FILTERBLIT_PLUS_ALPHABLEND, + gcvFEATURE_2D_DITHER, + gcvFEATURE_2D_A8_TARGET, + gcvFEATURE_2D_FILTERBLIT_FULLROTATION, + gcvFEATURE_2D_BITBLIT_FULLROTATION, + gcvFEATURE_WIDE_LINE, + gcvFEATURE_FC_FLUSH_STALL, + gcvFEATURE_FULL_DIRECTFB, + gcvFEATURE_HALF_FLOAT_PIPE, + gcvFEATURE_LINE_LOOP, + gcvFEATURE_2D_YUV_BLIT, + gcvFEATURE_2D_TILING, + gcvFEATURE_NON_POWER_OF_TWO, + gcvFEATURE_3D_TEXTURE, + gcvFEATURE_TEXTURE_ARRAY, + gcvFEATURE_TILE_FILLER, + gcvFEATURE_LOGIC_OP, + gcvFEATURE_COMPOSITION, + gcvFEATURE_MIXED_STREAMS, + gcvFEATURE_2D_MULTI_SOURCE_BLT, + gcvFEATURE_END_EVENT, + gcvFEATURE_VERTEX_10_10_10_2, + gcvFEATURE_TEXTURE_10_10_10_2, + gcvFEATURE_TEXTURE_ANISOTROPIC_FILTERING, + gcvFEATURE_TEXTURE_FLOAT_HALF_FLOAT, + gcvFEATURE_2D_ROTATION_STALL_FIX, + gcvFEATURE_2D_MULTI_SOURCE_BLT_EX, + gcvFEATURE_BUG_FIXES10, + gcvFEATURE_2D_MINOR_TILING, + /* Supertiled compressed textures are supported. */ + gcvFEATURE_TEX_COMPRRESSION_SUPERTILED, + gcvFEATURE_FAST_MSAA, + gcvFEATURE_BUG_FIXED_INDEXED_TRIANGLE_STRIP, + gcvFEATURE_TEXTURE_TILED_READ, + gcvFEATURE_DEPTH_BIAS_FIX, + gcvFEATURE_RECT_PRIMITIVE, + gcvFEATURE_BUG_FIXES11, + gcvFEATURE_SUPERTILED_TEXTURE, + gcvFEATURE_2D_NO_COLORBRUSH_INDEX8 +} +gceFEATURE; + +/* Chip Power Status. */ +typedef enum _gceCHIPPOWERSTATE +{ + gcvPOWER_ON = 0, + gcvPOWER_OFF, + gcvPOWER_IDLE, + gcvPOWER_SUSPEND, + gcvPOWER_SUSPEND_ATPOWERON, + gcvPOWER_OFF_ATPOWERON, + gcvPOWER_IDLE_BROADCAST, + gcvPOWER_SUSPEND_BROADCAST, + gcvPOWER_OFF_BROADCAST, + gcvPOWER_OFF_RECOVERY, +#if gcdPOWEROFF_TIMEOUT + gcvPOWER_OFF_TIMEOUT, +#endif + gcvPOWER_ON_AUTO +} +gceCHIPPOWERSTATE; + +/* CPU cache operations */ +typedef enum _gceCACHEOPERATION +{ + gcvCACHE_CLEAN = 0x01, + gcvCACHE_INVALIDATE = 0x02, + gcvCACHE_FLUSH = gcvCACHE_CLEAN | gcvCACHE_INVALIDATE, + gcvCACHE_MEMORY_BARRIER = 0x04 +} +gceCACHEOPERATION; + +typedef enum _gceVIDMEM_NODE_SHARED_INFO_TYPE +{ + gcvVIDMEM_INFO_GENERIC, + gcvVIDMEM_INFO_DIRTY_RECTANGLE +} +gceVIDMEM_NODE_SHARED_INFO_TYPE; + +/* Surface types. */ +typedef enum _gceSURF_TYPE +{ + gcvSURF_TYPE_UNKNOWN = 0, + gcvSURF_INDEX, + gcvSURF_VERTEX, + gcvSURF_TEXTURE, + gcvSURF_RENDER_TARGET, + gcvSURF_DEPTH, + gcvSURF_BITMAP, + gcvSURF_TILE_STATUS, + gcvSURF_IMAGE, + gcvSURF_MASK, + gcvSURF_SCISSOR, + gcvSURF_HIERARCHICAL_DEPTH, + gcvSURF_NUM_TYPES, /* Make sure this is the last one! */ + + /* Combinations. */ + gcvSURF_NO_TILE_STATUS = 0x100, + gcvSURF_NO_VIDMEM = 0x200, /* Used to allocate surfaces with no underlying vidmem node. + In Android, vidmem node is allocated by another process. */ + gcvSURF_CACHEABLE = 0x400, /* Used to allocate a cacheable surface */ +#if gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST + gcvSURF_FLIP = 0x800, /* The Resolve Target the will been flip resolve from RT */ +#endif + + gcvSURF_RENDER_TARGET_NO_TILE_STATUS = gcvSURF_RENDER_TARGET + | gcvSURF_NO_TILE_STATUS, + + gcvSURF_DEPTH_NO_TILE_STATUS = gcvSURF_DEPTH + | gcvSURF_NO_TILE_STATUS, + + /* Supported surface types with no vidmem node. */ + gcvSURF_BITMAP_NO_VIDMEM = gcvSURF_BITMAP + | gcvSURF_NO_VIDMEM, + + gcvSURF_TEXTURE_NO_VIDMEM = gcvSURF_TEXTURE + | gcvSURF_NO_VIDMEM, + + /* Cacheable surface types with no vidmem node. */ + gcvSURF_CACHEABLE_BITMAP_NO_VIDMEM = gcvSURF_BITMAP_NO_VIDMEM + | gcvSURF_CACHEABLE, + + gcvSURF_CACHEABLE_BITMAP = gcvSURF_BITMAP + | gcvSURF_CACHEABLE, + +#if gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST + gcvSURF_FLIP_BITMAP = gcvSURF_BITMAP + | gcvSURF_FLIP, +#endif +} +gceSURF_TYPE; + +typedef enum _gceSURF_USAGE +{ + gcvSURF_USAGE_UNKNOWN, + gcvSURF_USAGE_RESOLVE_AFTER_CPU, + gcvSURF_USAGE_RESOLVE_AFTER_3D +} +gceSURF_USAGE; + +typedef enum _gceSURF_COLOR_TYPE +{ + gcvSURF_COLOR_UNKNOWN = 0, + gcvSURF_COLOR_LINEAR = 0x01, + gcvSURF_COLOR_ALPHA_PRE = 0x02, +} +gceSURF_COLOR_TYPE; + +/* Rotation. */ +typedef enum _gceSURF_ROTATION +{ + gcvSURF_0_DEGREE = 0, + gcvSURF_90_DEGREE, + gcvSURF_180_DEGREE, + gcvSURF_270_DEGREE, + gcvSURF_FLIP_X, + gcvSURF_FLIP_Y, +} +gceSURF_ROTATION; + +/* Surface formats. */ +typedef enum _gceSURF_FORMAT +{ + /* Unknown format. */ + gcvSURF_UNKNOWN = 0, + + /* Palettized formats. */ + gcvSURF_INDEX1 = 100, + gcvSURF_INDEX4, + gcvSURF_INDEX8, + + /* RGB formats. */ + gcvSURF_A2R2G2B2 = 200, + gcvSURF_R3G3B2, + gcvSURF_A8R3G3B2, + gcvSURF_X4R4G4B4, + gcvSURF_A4R4G4B4, + gcvSURF_R4G4B4A4, + gcvSURF_X1R5G5B5, + gcvSURF_A1R5G5B5, + gcvSURF_R5G5B5A1, + gcvSURF_R5G6B5, + gcvSURF_R8G8B8, + gcvSURF_X8R8G8B8, + gcvSURF_A8R8G8B8, + gcvSURF_R8G8B8A8, + gcvSURF_G8R8G8B8, + gcvSURF_R8G8B8G8, + gcvSURF_X2R10G10B10, + gcvSURF_A2R10G10B10, + gcvSURF_X12R12G12B12, + gcvSURF_A12R12G12B12, + gcvSURF_X16R16G16B16, + gcvSURF_A16R16G16B16, + gcvSURF_A32R32G32B32, + gcvSURF_R8G8B8X8, + gcvSURF_R5G5B5X1, + gcvSURF_R4G4B4X4, + + /* BGR formats. */ + gcvSURF_A4B4G4R4 = 300, + gcvSURF_A1B5G5R5, + gcvSURF_B5G6R5, + gcvSURF_B8G8R8, + gcvSURF_B16G16R16, + gcvSURF_X8B8G8R8, + gcvSURF_A8B8G8R8, + gcvSURF_A2B10G10R10, + gcvSURF_X16B16G16R16, + gcvSURF_A16B16G16R16, + gcvSURF_B32G32R32, + gcvSURF_X32B32G32R32, + gcvSURF_A32B32G32R32, + gcvSURF_B4G4R4A4, + gcvSURF_B5G5R5A1, + gcvSURF_B8G8R8X8, + gcvSURF_B8G8R8A8, + gcvSURF_X4B4G4R4, + gcvSURF_X1B5G5R5, + gcvSURF_B4G4R4X4, + gcvSURF_B5G5R5X1, + gcvSURF_X2B10G10R10, + + /* Compressed formats. */ + gcvSURF_DXT1 = 400, + gcvSURF_DXT2, + gcvSURF_DXT3, + gcvSURF_DXT4, + gcvSURF_DXT5, + gcvSURF_CXV8U8, + gcvSURF_ETC1, + + /* YUV formats. */ + gcvSURF_YUY2 = 500, + gcvSURF_UYVY, + gcvSURF_YV12, + gcvSURF_I420, + gcvSURF_NV12, + gcvSURF_NV21, + gcvSURF_NV16, + gcvSURF_NV61, + gcvSURF_YVYU, + gcvSURF_VYUY, + + /* Depth formats. */ + gcvSURF_D16 = 600, + gcvSURF_D24S8, + gcvSURF_D32, + gcvSURF_D24X8, + + /* Alpha formats. */ + gcvSURF_A4 = 700, + gcvSURF_A8, + gcvSURF_A12, + gcvSURF_A16, + gcvSURF_A32, + gcvSURF_A1, + + /* Luminance formats. */ + gcvSURF_L4 = 800, + gcvSURF_L8, + gcvSURF_L12, + gcvSURF_L16, + gcvSURF_L32, + gcvSURF_L1, + + /* Alpha/Luminance formats. */ + gcvSURF_A4L4 = 900, + gcvSURF_A2L6, + gcvSURF_A8L8, + gcvSURF_A4L12, + gcvSURF_A12L12, + gcvSURF_A16L16, + + /* Bump formats. */ + gcvSURF_L6V5U5 = 1000, + gcvSURF_V8U8, + gcvSURF_X8L8V8U8, + gcvSURF_Q8W8V8U8, + gcvSURF_A2W10V10U10, + gcvSURF_V16U16, + gcvSURF_Q16W16V16U16, + + /* R/RG/RA formats. */ + gcvSURF_R8 = 1100, + gcvSURF_X8R8, + gcvSURF_G8R8, + gcvSURF_X8G8R8, + gcvSURF_A8R8, + gcvSURF_R16, + gcvSURF_X16R16, + gcvSURF_G16R16, + gcvSURF_X16G16R16, + gcvSURF_A16R16, + gcvSURF_R32, + gcvSURF_X32R32, + gcvSURF_G32R32, + gcvSURF_X32G32R32, + gcvSURF_A32R32, + gcvSURF_RG16, + + /* Floating point formats. */ + gcvSURF_R16F = 1200, + gcvSURF_X16R16F, + gcvSURF_G16R16F, + gcvSURF_X16G16R16F, + gcvSURF_B16G16R16F, + gcvSURF_X16B16G16R16F, + gcvSURF_A16B16G16R16F, + gcvSURF_R32F, + gcvSURF_X32R32F, + gcvSURF_G32R32F, + gcvSURF_X32G32R32F, + gcvSURF_B32G32R32F, + gcvSURF_X32B32G32R32F, + gcvSURF_A32B32G32R32F, + gcvSURF_A16F, + gcvSURF_L16F, + gcvSURF_A16L16F, + gcvSURF_A16R16F, + gcvSURF_A32F, + gcvSURF_L32F, + gcvSURF_A32L32F, + gcvSURF_A32R32F, + +} +gceSURF_FORMAT; + +/* Pixel swizzle modes. */ +typedef enum _gceSURF_SWIZZLE +{ + gcvSURF_NOSWIZZLE = 0, + gcvSURF_ARGB, + gcvSURF_ABGR, + gcvSURF_RGBA, + gcvSURF_BGRA +} +gceSURF_SWIZZLE; + +/* Transparency modes. */ +typedef enum _gceSURF_TRANSPARENCY +{ + /* Valid only for PE 1.0 */ + gcvSURF_OPAQUE = 0, + gcvSURF_SOURCE_MATCH, + gcvSURF_SOURCE_MASK, + gcvSURF_PATTERN_MASK, +} +gceSURF_TRANSPARENCY; + +/* Surface Alignment. */ +typedef enum _gceSURF_ALIGNMENT +{ + gcvSURF_FOUR = 0, + gcvSURF_SIXTEEN, + gcvSURF_SUPER_TILED, + gcvSURF_SPLIT_TILED, + gcvSURF_SPLIT_SUPER_TILED, +} +gceSURF_ALIGNMENT; + +/* Transparency modes. */ +typedef enum _gce2D_TRANSPARENCY +{ + /* Valid only for PE 2.0 */ + gcv2D_OPAQUE = 0, + gcv2D_KEYED, + gcv2D_MASKED +} +gce2D_TRANSPARENCY; + +/* Mono packing modes. */ +typedef enum _gceSURF_MONOPACK +{ + gcvSURF_PACKED8 = 0, + gcvSURF_PACKED16, + gcvSURF_PACKED32, + gcvSURF_UNPACKED, +} +gceSURF_MONOPACK; + +/* Blending modes. */ +typedef enum _gceSURF_BLEND_MODE +{ + /* Porter-Duff blending modes. */ + /* Fsrc Fdst */ + gcvBLEND_CLEAR = 0, /* 0 0 */ + gcvBLEND_SRC, /* 1 0 */ + gcvBLEND_DST, /* 0 1 */ + gcvBLEND_SRC_OVER_DST, /* 1 1 - Asrc */ + gcvBLEND_DST_OVER_SRC, /* 1 - Adst 1 */ + gcvBLEND_SRC_IN_DST, /* Adst 0 */ + gcvBLEND_DST_IN_SRC, /* 0 Asrc */ + gcvBLEND_SRC_OUT_DST, /* 1 - Adst 0 */ + gcvBLEND_DST_OUT_SRC, /* 0 1 - Asrc */ + gcvBLEND_SRC_ATOP_DST, /* Adst 1 - Asrc */ + gcvBLEND_DST_ATOP_SRC, /* 1 - Adst Asrc */ + gcvBLEND_SRC_XOR_DST, /* 1 - Adst 1 - Asrc */ + + /* Special blending modes. */ + gcvBLEND_SET, /* DST = 1 */ + gcvBLEND_SUB /* DST = DST * (1 - SRC) */ +} +gceSURF_BLEND_MODE; + +/* Per-pixel alpha modes. */ +typedef enum _gceSURF_PIXEL_ALPHA_MODE +{ + gcvSURF_PIXEL_ALPHA_STRAIGHT = 0, + gcvSURF_PIXEL_ALPHA_INVERSED +} +gceSURF_PIXEL_ALPHA_MODE; + +/* Global alpha modes. */ +typedef enum _gceSURF_GLOBAL_ALPHA_MODE +{ + gcvSURF_GLOBAL_ALPHA_OFF = 0, + gcvSURF_GLOBAL_ALPHA_ON, + gcvSURF_GLOBAL_ALPHA_SCALE +} +gceSURF_GLOBAL_ALPHA_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gceSURF_PIXEL_COLOR_MODE +{ + gcvSURF_COLOR_STRAIGHT = 0, + gcvSURF_COLOR_MULTIPLY +} +gceSURF_PIXEL_COLOR_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_PIXEL_COLOR_MULTIPLY_MODE +{ + gcv2D_COLOR_MULTIPLY_DISABLE = 0, + gcv2D_COLOR_MULTIPLY_ENABLE +} +gce2D_PIXEL_COLOR_MULTIPLY_MODE; + +/* Color component modes for alpha blending. */ +typedef enum _gce2D_GLOBAL_COLOR_MULTIPLY_MODE +{ + gcv2D_GLOBAL_COLOR_MULTIPLY_DISABLE = 0, + gcv2D_GLOBAL_COLOR_MULTIPLY_ALPHA, + gcv2D_GLOBAL_COLOR_MULTIPLY_COLOR +} +gce2D_GLOBAL_COLOR_MULTIPLY_MODE; + +/* Alpha blending factor modes. */ +typedef enum _gceSURF_BLEND_FACTOR_MODE +{ + gcvSURF_BLEND_ZERO = 0, + gcvSURF_BLEND_ONE, + gcvSURF_BLEND_STRAIGHT, + gcvSURF_BLEND_INVERSED, + gcvSURF_BLEND_COLOR, + gcvSURF_BLEND_COLOR_INVERSED, + gcvSURF_BLEND_SRC_ALPHA_SATURATED, + gcvSURF_BLEND_STRAIGHT_NO_CROSS, + gcvSURF_BLEND_INVERSED_NO_CROSS, + gcvSURF_BLEND_COLOR_NO_CROSS, + gcvSURF_BLEND_COLOR_INVERSED_NO_CROSS, + gcvSURF_BLEND_SRC_ALPHA_SATURATED_CROSS +} +gceSURF_BLEND_FACTOR_MODE; + +/* Alpha blending porter duff rules. */ +typedef enum _gce2D_PORTER_DUFF_RULE +{ + gcvPD_CLEAR = 0, + gcvPD_SRC, + gcvPD_SRC_OVER, + gcvPD_DST_OVER, + gcvPD_SRC_IN, + gcvPD_DST_IN, + gcvPD_SRC_OUT, + gcvPD_DST_OUT, + gcvPD_SRC_ATOP, + gcvPD_DST_ATOP, + gcvPD_ADD, + gcvPD_XOR, + gcvPD_DST +} +gce2D_PORTER_DUFF_RULE; + +/* Alpha blending factor modes. */ +typedef enum _gce2D_YUV_COLOR_MODE +{ + gcv2D_YUV_601= 0, + gcv2D_YUV_709 +} +gce2D_YUV_COLOR_MODE; + +/* 2D Rotation and flipping. */ +typedef enum _gce2D_ORIENTATION +{ + gcv2D_0_DEGREE = 0, + gcv2D_90_DEGREE, + gcv2D_180_DEGREE, + gcv2D_270_DEGREE, + gcv2D_X_FLIP, + gcv2D_Y_FLIP +} +gce2D_ORIENTATION; + +typedef enum _gce2D_COMMAND +{ + gcv2D_CLEAR = 0, + gcv2D_LINE, + gcv2D_BLT, + gcv2D_STRETCH, + gcv2D_HOR_FILTER, + gcv2D_VER_FILTER, + gcv2D_MULTI_SOURCE_BLT, +} +gce2D_COMMAND; + +#ifndef VIVANTE_NO_3D +/* Texture functions. */ +typedef enum _gceTEXTURE_FUNCTION +{ + gcvTEXTURE_DUMMY = 0, + gcvTEXTURE_REPLACE = 0, + gcvTEXTURE_MODULATE, + gcvTEXTURE_ADD, + gcvTEXTURE_ADD_SIGNED, + gcvTEXTURE_INTERPOLATE, + gcvTEXTURE_SUBTRACT, + gcvTEXTURE_DOT3 +} +gceTEXTURE_FUNCTION; + +/* Texture sources. */ +typedef enum _gceTEXTURE_SOURCE +{ + gcvCOLOR_FROM_TEXTURE = 0, + gcvCOLOR_FROM_CONSTANT_COLOR, + gcvCOLOR_FROM_PRIMARY_COLOR, + gcvCOLOR_FROM_PREVIOUS_COLOR +} +gceTEXTURE_SOURCE; + +/* Texture source channels. */ +typedef enum _gceTEXTURE_CHANNEL +{ + gcvFROM_COLOR = 0, + gcvFROM_ONE_MINUS_COLOR, + gcvFROM_ALPHA, + gcvFROM_ONE_MINUS_ALPHA +} +gceTEXTURE_CHANNEL; +#endif /* VIVANTE_NO_3D */ + +/* Filter types. */ +typedef enum _gceFILTER_TYPE +{ + gcvFILTER_SYNC = 0, + gcvFILTER_BLUR, + gcvFILTER_USER +} +gceFILTER_TYPE; + +/* Filter pass types. */ +typedef enum _gceFILTER_PASS_TYPE +{ + gcvFILTER_HOR_PASS = 0, + gcvFILTER_VER_PASS +} +gceFILTER_PASS_TYPE; + +/* Endian hints. */ +typedef enum _gceENDIAN_HINT +{ + gcvENDIAN_NO_SWAP = 0, + gcvENDIAN_SWAP_WORD, + gcvENDIAN_SWAP_DWORD +} +gceENDIAN_HINT; + +/* Tiling modes. */ +typedef enum _gceTILING +{ + gcvLINEAR = 0, + gcvTILED, + gcvSUPERTILED, + gcvMULTI_TILED, + gcvMULTI_SUPERTILED, + gcvMINORTILED, +} +gceTILING; + +/* 2D pattern type. */ +typedef enum _gce2D_PATTERN +{ + gcv2D_PATTERN_SOLID = 0, + gcv2D_PATTERN_MONO, + gcv2D_PATTERN_COLOR, + gcv2D_PATTERN_INVALID +} +gce2D_PATTERN; + +/* 2D source type. */ +typedef enum _gce2D_SOURCE +{ + gcv2D_SOURCE_MASKED = 0, + gcv2D_SOURCE_MONO, + gcv2D_SOURCE_COLOR, + gcv2D_SOURCE_INVALID +} +gce2D_SOURCE; + +/* Pipes. */ +typedef enum _gcePIPE_SELECT +{ + gcvPIPE_INVALID = ~0, + gcvPIPE_3D = 0, + gcvPIPE_2D +} +gcePIPE_SELECT; + +/* Hardware type. */ +typedef enum _gceHARDWARE_TYPE +{ + gcvHARDWARE_INVALID = 0x00, + gcvHARDWARE_3D = 0x01, + gcvHARDWARE_2D = 0x02, + gcvHARDWARE_VG = 0x04, + + gcvHARDWARE_3D2D = gcvHARDWARE_3D | gcvHARDWARE_2D +} +gceHARDWARE_TYPE; + +#define gcdCHIP_COUNT 3 + +typedef enum _gceMMU_MODE +{ + gcvMMU_MODE_1K, + gcvMMU_MODE_4K, +} gceMMU_MODE; + +/* User signal command codes. */ +typedef enum _gceUSER_SIGNAL_COMMAND_CODES +{ + gcvUSER_SIGNAL_CREATE, + gcvUSER_SIGNAL_DESTROY, + gcvUSER_SIGNAL_SIGNAL, + gcvUSER_SIGNAL_WAIT, + gcvUSER_SIGNAL_MAP, + gcvUSER_SIGNAL_UNMAP, +} +gceUSER_SIGNAL_COMMAND_CODES; + +/* Event locations. */ +typedef enum _gceKERNEL_WHERE +{ + gcvKERNEL_COMMAND, + gcvKERNEL_VERTEX, + gcvKERNEL_TRIANGLE, + gcvKERNEL_TEXTURE, + gcvKERNEL_PIXEL, +} +gceKERNEL_WHERE; + +#if gcdENABLE_VG +/* Hardware blocks. */ +typedef enum _gceBLOCK +{ + gcvBLOCK_COMMAND, + gcvBLOCK_TESSELLATOR, + gcvBLOCK_TESSELLATOR2, + gcvBLOCK_TESSELLATOR3, + gcvBLOCK_RASTER, + gcvBLOCK_VG, + gcvBLOCK_VG2, + gcvBLOCK_VG3, + gcvBLOCK_PIXEL, + + /* Number of defined blocks. */ + gcvBLOCK_COUNT +} +gceBLOCK; +#endif + +/* gcdDUMP message type. */ +typedef enum _gceDEBUG_MESSAGE_TYPE +{ + gcvMESSAGE_TEXT, + gcvMESSAGE_DUMP +} +gceDEBUG_MESSAGE_TYPE; + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gckCONTEXT * gckCONTEXT; +typedef struct _gcoCMDBUF * gcoCMDBUF; +typedef struct _gcsSTATE_DELTA * gcsSTATE_DELTA_PTR; +typedef struct _gcsQUEUE * gcsQUEUE_PTR; +typedef struct _gcoQUEUE * gcoQUEUE; +typedef struct _gcsHAL_INTERFACE * gcsHAL_INTERFACE_PTR; +typedef struct _gcs2D_PROFILE * gcs2D_PROFILE_PTR; + +#if gcdENABLE_VG +typedef struct _gcoVGHARDWARE * gcoVGHARDWARE; +typedef struct _gcoVGBUFFER * gcoVGBUFFER; +typedef struct _gckVGHARDWARE * gckVGHARDWARE; +typedef struct _gcsVGCONTEXT * gcsVGCONTEXT_PTR; +typedef struct _gcsVGCONTEXT_MAP * gcsVGCONTEXT_MAP_PTR; +typedef struct _gcsVGCMDQUEUE * gcsVGCMDQUEUE_PTR; +typedef struct _gcsTASK_MASTER_TABLE * gcsTASK_MASTER_TABLE_PTR; +typedef struct _gckVGKERNEL * gckVGKERNEL; +typedef void * gctTHREAD; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_enum_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_kernel_buffer.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_kernel_buffer.h new file mode 100644 index 0000000..24edc0b --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_kernel_buffer.h @@ -0,0 +1,192 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_buffer_h_ +#define __gc_hal_kernel_buffer_h_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +************************ Command Buffer and Event Objects ********************** +\******************************************************************************/ + +/* The number of context buffers per user. */ +#define gcdCONTEXT_BUFFER_COUNT 2 + +/* State delta record. */ +typedef struct _gcsSTATE_DELTA_RECORD * gcsSTATE_DELTA_RECORD_PTR; +typedef struct _gcsSTATE_DELTA_RECORD +{ + /* State address. */ + gctUINT address; + + /* State mask. */ + gctUINT32 mask; + + /* State data. */ + gctUINT32 data; +} +gcsSTATE_DELTA_RECORD; + +/* State delta. */ +typedef struct _gcsSTATE_DELTA +{ + /* For debugging: the number of delta in the order of creation. */ +#if gcmIS_DEBUG(gcdDEBUG_CODE) + gctUINT num; +#endif + + /* For dumping. */ +#if gcdDUMP + gcoOS os; +#endif + + /* Main state delta ID. Every time state delta structure gets reinitialized, + main ID is incremented. If main state ID overflows, all map entry IDs get + reinitialized to make sure there is no potential erroneous match after + the overflow.*/ + gctUINT id; + + /* The number of contexts pending modification by the delta. */ + gctINT refCount; + + /* Vertex element count for the delta buffer. */ + gctUINT elementCount; + + /* Number of states currently stored in the record array. */ + gctUINT recordCount; + + /* Record array; holds all modified states. */ + gcsSTATE_DELTA_RECORD_PTR recordArray; + + /* Map entry ID is used for map entry validation. If map entry ID does not + match the main state delta ID, the entry and the corresponding state are + considered not in use. */ + gctUINT_PTR mapEntryID; + gctUINT mapEntryIDSize; + + /* If the map entry ID matches the main state delta ID, index points to + the state record in the record array. */ + gctUINT_PTR mapEntryIndex; + + /* Previous and next state deltas. */ + gcsSTATE_DELTA_PTR prev; + gcsSTATE_DELTA_PTR next; +} +gcsSTATE_DELTA; + +/* Command buffer object. */ +struct _gcoCMDBUF +{ + /* The object. */ + gcsOBJECT object; + + /* Command buffer entry and exit pipes. */ + gcePIPE_SELECT entryPipe; + gcePIPE_SELECT exitPipe; + + /* Feature usage flags. */ + gctBOOL using2D; + gctBOOL using3D; + gctBOOL usingFilterBlit; + gctBOOL usingPalette; + + /* Physical address of command buffer. */ + gctPHYS_ADDR physical; + + /* Logical address of command buffer. */ + gctPOINTER logical; + + /* Number of bytes in command buffer. */ + gctSIZE_T bytes; + + /* Start offset into the command buffer. */ + gctUINT32 startOffset; + + /* Current offset into the command buffer. */ + gctUINT32 offset; + + /* Number of free bytes in command buffer. */ + gctSIZE_T free; + + /* Location of the last reserved area. */ + gctPOINTER lastReserve; + gctUINT lastOffset; + +#if gcdSECURE_USER + /* Hint array for the current command buffer. */ + gctUINT hintArraySize; + gctUINT32_PTR hintArray; + gctUINT32_PTR hintArrayTail; +#endif + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + /* Last load state command location and hardware address. */ + gctUINT32_PTR lastLoadStatePtr; + gctUINT32 lastLoadStateAddress; + gctUINT32 lastLoadStateCount; +#endif +}; + +typedef struct _gcsQUEUE +{ + /* Pointer to next gcsQUEUE structure. */ + gcsQUEUE_PTR next; + + /* Event information. */ + gcsHAL_INTERFACE iface; +} +gcsQUEUE; + +/* Event queue. */ +struct _gcoQUEUE +{ + /* The object. */ + gcsOBJECT object; + + /* Pointer to current event queue. */ + gcsQUEUE_PTR head; + gcsQUEUE_PTR tail; + +#ifdef __QNXNTO__ + /* Buffer for records. */ + gcsQUEUE_PTR records; + gctUINT32 freeBytes; + gctUINT32 offset; +#else + /* List of free records. */ + gcsQUEUE_PTR freeList; +#endif + #define gcdIN_QUEUE_RECORD_LIMIT 16 + /* Number of records currently in queue */ + gctUINT32 recordCount; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_buffer_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_md5.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_md5.h new file mode 100644 index 0000000..ac0f973 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_md5.h @@ -0,0 +1,112 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: gc_hal_md5.h,v 1.1.6.1 2012/02/09 00:22:42 semih.demirer Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + + +#ifndef __gc_hal_md5_h_ +#define __gc_hal_md5_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char gctMD5_Byte; /* 8-bit byte */ +typedef unsigned int gctMD5_Word; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct _gcsMD5_State { + gctMD5_Word count[2]; /* message length in bits, lsw first */ + gctMD5_Word abcd[4]; /* digest buffer */ + gctMD5_Byte buf[64]; /* accumulate block */ +} gcsMD5_State; + +/* Initialize the algorithm. */ +void gcoMD5_Init(gcsMD5_State *pms); + +/* Append a string to the message. */ +void gcoMD5_Append(gcsMD5_State *pms, const gctMD5_Byte *data, int nbytes); + +/* Finish the message and return the digest. */ +void gcoMD5_Finish(gcsMD5_State *pms, gctMD5_Byte digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_mem.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_mem.h new file mode 100644 index 0000000..e64f7e7 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_mem.h @@ -0,0 +1,532 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +/* +** Include file for the local memory management. +*/ + +#ifndef __gc_hal_mem_h_ +#define __gc_hal_mem_h_ +#ifndef VIVANTE_NO_3D + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* +** Usage: + + The macros to declare MemPool type and functions are + gcmMEM_DeclareFSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareVSMemPool (Type, TypeName, Prefix) + gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) + + The data structures for MemPool are + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; + + The MemPool constructor and destructor functions are + gcfMEM_InitFSMemPool(gcsMEM_FS_MEM_POOL *, gcoOS, gctUINT, gctUINT); + gcfMEM_FreeFSMemPool(gcsMEM_FS_MEM_POOL *); + gcfMEM_InitVSMemPool(gcsMEM_VS_MEM_POOL *, gcoOS, gctUINT, gctBOOL); + gcfMEM_FreeVSMemPool(gcsMEM_VS_MEM_POOL *); + gcfMEM_InitAFSMemPool(gcsMEM_AFS_MEM_POOL *, gcoOS, gctUINT); + gcfMEM_FreeAFSMemPool(gcsMEM_AFS_MEM_POOL *); + + FS: for Fixed-Size data structures + VS: for Variable-size data structures + AFS: for Array of Fixed-Size data structures + + + // Example 1: For a fixed-size data structure, struct gcsNode. + // It is used locally in a file, so the functions are static without prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type. + // The second armument is the short name used in the fuctions. + gcmMEM_DeclareFSMemPool(struct gcsNode, Node, ); + + // The previous macro creates two inline functions, + // _AllocateNode and _FreeNode. + + // In function or struct + gcsMEM_FS_MEM_POOL nodeMemPool; + + // In function, + struct gcsNode * node; + gceSTATUS status; + + // Before using the memory pool, initialize it. + // The second argument is the gcoOS object. + // The third argument is the number of data structures to allocate for each chunk. + status = gcfMEM_InitFSMemPool(&nodeMemPool, os, 100, sizeof(struct gcsNode)); + ... + + // Allocate a node. + status = _AllocateNode(nodeMemPool, &node); + ... + // Free a node. + _FreeNode(nodeMemPool, node); + + // After using the memory pool, free it. + gcfMEM_FreeFSMemPool(&nodeMemPool); + + + // Example 2: For array of fixed-size data structures, struct gcsNode. + // It is used in several files, so the functions are extern with prefix. + // At top level, declear allocate and free functions. + // The first argument is the data type, and the second one is the short name + // used in the fuctions. + gcmMEM_DeclareAFSMemPool(struct gcsNode, NodeArray, gcfOpt); + + // The previous macro creates two inline functions, + // gcfOpt_AllocateNodeArray and gcfOpt_FreeNodeArray. + + // In function or struct + gcsMEM_AFS_MEM_POOL nodeArrayMemPool; + + // In function, + struct gcsNode * nodeArray; + gceSTATUS status; + + // Before using the array memory pool, initialize it. + // The second argument is the gcoOS object, the third is the number of data + // structures to allocate for each chunk. + status = gcfMEM_InitAFSMemPool(&nodeArrayMemPool, os, sizeof(struct gcsNode)); + ... + + // Allocate a node array of size 100. + status = gcfOpt_AllocateNodeArray(nodeArrayMemPool, &nodeArray, 100); + ... + // Free a node array. + gcfOpt_FreeNodeArray(&nodeArrayMemPool, nodeArray); + + // After using the array memory pool, free it. + gcfMEM_FreeAFSMemPool(&nodeArrayMemPool); + +*******************************************************************************/ + +/******************************************************************************* +** To switch back to use gcoOS_Allocate and gcoOS_Free, add +** #define USE_LOCAL_MEMORY_POOL 0 +** before including this file. +*******************************************************************************/ +#ifndef USE_LOCAL_MEMORY_POOL +/* + USE_LOCAL_MEMORY_POOL + + This define enables the local memory management to improve performance. +*/ +#define USE_LOCAL_MEMORY_POOL 1 +#endif + +/******************************************************************************* +** Memory Pool Data Structures +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL + typedef struct _gcsMEM_FS_MEM_POOL * gcsMEM_FS_MEM_POOL; + typedef struct _gcsMEM_VS_MEM_POOL * gcsMEM_VS_MEM_POOL; + typedef struct _gcsMEM_AFS_MEM_POOL * gcsMEM_AFS_MEM_POOL; +#else + typedef gcoOS gcsMEM_FS_MEM_POOL; + typedef gcoOS gcsMEM_VS_MEM_POOL; + typedef gcoOS gcsMEM_AFS_MEM_POOL; +#endif + +/******************************************************************************* +** Memory Pool Macros +*******************************************************************************/ +#if USE_LOCAL_MEMORY_POOL +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + return(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + gcmERR_RETURN(gcfMEM_FSMemPoolGetANode(MemPool, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcfMEM_FSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName##List( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * FirstPointer, \ + Type * LastPointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x FirstPointer=0x%x LastPointer=0x%x", MemPool, FirstPointer, LastPointer); \ + status = gcfMEM_FSMemPoolFreeAList(MemPool, (gctPOINTER) FirstPointer, (gctPOINTER) LastPointer); \ + gcmFOOTER(); \ + return status; \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status;\ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ + status = gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ + Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ + gcmERR_RETURN(gcfMEM_VSMemPoolGetANode(MemPool, Size, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, size)); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pinter); \ + status = gcfMEM_VSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ + gcmFOOTER(); \ + return status; \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ + status = gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ + gcmERR_RETURN(gcfMEM_AFSMemPoolGetANode(MemPool, Count, (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcfMEM_AFSMemPoolFreeANode(MemPool, (gctPOINTER) Pointer); \ + gcmFOOTER(); \ + return status; \ +} + +#else + +#define gcmMEM_DeclareFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type ** Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, gcmSIZEOF(Type))); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_FS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcmOS_SAFE_FREE(MemPool, Pointer); \ + gcmFOOTER(); \ + return status; \ +} + +#define gcmMEM_DeclareVSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ + status = gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Size \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Size=%u", MemPool, Pointer, Size); \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Size, \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Size)); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_VS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcmOS_SAFE_FREE(MemPool, Pointer); \ + gcmFOOTER(); \ + return status; \ +} + +#define gcmMEM_DeclareAFSMemPool(Type, TypeName, Prefix) \ +gceSTATUS \ +Prefix##_Allocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ + status = gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer); \ + gcmFOOTER(); \ + return status; \ +} \ + \ +gceSTATUS \ +Prefix##_CAllocate##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type ** Pointer, \ + gctUINT Count \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x Count=%u", MemPool, Pointer, Count); \ + gcmERR_RETURN(gcoOS_Allocate(MemPool, \ + Count * gcmSIZEOF(Type), \ + (gctPOINTER *) Pointer)); \ + gcmVERIFY_OK(gcoOS_ZeroMemory(*(gctPOINTER *) Pointer, Count * gcmSIZEOF(Type))); \ + gcmFOOTER(); \ + return gcvSTATUS_OK; \ +} \ + \ +gceSTATUS \ +Prefix##_Free##TypeName( \ + gcsMEM_AFS_MEM_POOL MemPool, \ + Type * Pointer \ + ) \ +{ \ + gceSTATUS status; \ + gcmHEADER_ARG("MemPool=0x%x Pointer=0x%x", MemPool, Pointer); \ + status = gcmOS_SAFE_FREE(MemPool, Pointer); \ + gcmFOOTER(); \ + return status; \ +} +#endif + +/******************************************************************************* +** Memory Pool Data Functions +*******************************************************************************/ +gceSTATUS +gcfMEM_InitFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeFSMemPool( + IN gcsMEM_FS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_FSMemPoolGetANode( + IN gcsMEM_FS_MEM_POOL MemPool, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeANode( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_FSMemPoolFreeAList( + IN gcsMEM_FS_MEM_POOL MemPool, + IN gctPOINTER FirstNode, + IN gctPOINTER LastNode + ); + +gceSTATUS +gcfMEM_InitVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool, + IN gcoOS OS, + IN gctUINT BlockSize, + IN gctBOOL RecycleFreeNode + ); + +gceSTATUS +gcfMEM_FreeVSMemPool( + IN gcsMEM_VS_MEM_POOL * MemPool + ); + +gceSTATUS +gcfMEM_VSMemPoolGetANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctUINT Size, + IN gctUINT Alignment, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_VSMemPoolFreeANode( + IN gcsMEM_VS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +gceSTATUS +gcfMEM_InitAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool, + IN gcoOS OS, + IN gctUINT NodeCount, + IN gctUINT NodeSize + ); + +gceSTATUS +gcfMEM_FreeAFSMemPool( + IN gcsMEM_AFS_MEM_POOL *MemPool + ); + +gceSTATUS +gcfMEM_AFSMemPoolGetANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctUINT Count, + OUT gctPOINTER * Node + ); + +gceSTATUS +gcfMEM_AFSMemPoolFreeANode( + IN gcsMEM_AFS_MEM_POOL MemPool, + IN gctPOINTER Node + ); + +#ifdef __cplusplus +} +#endif + +#endif /* VIVANTE_NO_3D */ +#endif /* __gc_hal_mem_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_options.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_options.h new file mode 100644 index 0000000..d01804f --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_options.h @@ -0,0 +1,756 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_options_h_ +#define __gc_hal_options_h_ + +/* + gcdPRINT_VERSION + + Print HAL version. +*/ +#ifndef gcdPRINT_VERSION +# define gcdPRINT_VERSION 0 +#endif + +/* + USE_NEW_LINUX_SIGNAL + + This define enables the Linux kernel signaling between kernel and user. +*/ +#ifndef USE_NEW_LINUX_SIGNAL +# define USE_NEW_LINUX_SIGNAL 0 +#endif + +/* + NO_USER_DIRECT_ACCESS_FROM_KERNEL + + This define enables the Linux kernel behavior accessing user memory. +*/ +#ifndef NO_USER_DIRECT_ACCESS_FROM_KERNEL +# define NO_USER_DIRECT_ACCESS_FROM_KERNEL 0 +#endif + +/* + VIVANTE_PROFILER + + This define enables the profiler. +*/ +#ifndef VIVANTE_PROFILER +# define VIVANTE_PROFILER 0 +#endif + +/* + gcdUSE_VG + + Enable VG HAL layer (only for GC350). +*/ +#ifndef gcdUSE_VG +# define gcdUSE_VG 0 +#endif + +/* + USE_SW_FB + + Set to 1 if the frame buffer memory cannot be accessed by the GPU. +*/ +#ifndef USE_SW_FB +# define USE_SW_FB 0 +#endif + +/* + USE_SUPER_SAMPLING + + This define enables super-sampling support. +*/ +#define USE_SUPER_SAMPLING 0 + +/* + PROFILE_HAL_COUNTERS + + This define enables HAL counter profiling support. HW and SHADER + counter profiling depends on this. +*/ +#ifndef PROFILE_HAL_COUNTERS +# define PROFILE_HAL_COUNTERS 1 +#endif + +/* + PROFILE_HW_COUNTERS + + This define enables HW counter profiling support. +*/ +#ifndef PROFILE_HW_COUNTERS +# define PROFILE_HW_COUNTERS 1 +#endif + +/* + PROFILE_SHADER_COUNTERS + + This define enables SHADER counter profiling support. +*/ +#ifndef PROFILE_SHADER_COUNTERS +# define PROFILE_SHADER_COUNTERS 1 +#endif + +/* + COMMAND_PROCESSOR_VERSION + + The version of the command buffer and task manager. +*/ +#define COMMAND_PROCESSOR_VERSION 1 + +/* + gcdDUMP + + When set to 1, a dump of all states and memory uploads, as well as other + hardware related execution will be printed to the debug console. This + data can be used for playing back applications. +*/ +#ifndef gcdDUMP +# define gcdDUMP 0 +#endif + +/* + gcdDUMP_API + + When set to 1, a high level dump of the EGL and GL/VG APs's are + captured. +*/ +#ifndef gcdDUMP_API +# define gcdDUMP_API 0 +#endif + +/* + gcdDUMP_FRAMERATE + When set to a value other than zero, averaqe frame rate will be dumped. + The value set is the starting frame that the average will be calculated. + This is needed because sometimes first few frames are too slow to be included + in the average. Frame count starts from 1. +*/ +#ifndef gcdDUMP_FRAMERATE +# define gcdDUMP_FRAMERATE 0 +#endif + + +/* + gcdDUMP_IN_KERNEL + + When set to 1, all dumps will happen in the kernel. This is handy if + you want the kernel to dump its command buffers as well and the data + needs to be in sync. +*/ +#ifndef gcdDUMP_IN_KERNEL +# define gcdDUMP_IN_KERNEL 0 +#endif + +/* + gcdDUMP_COMMAND + + When set to non-zero, the command queue will dump all incoming command + and context buffers as well as all other modifications to the command + queue. +*/ +#ifndef gcdDUMP_COMMAND +# define gcdDUMP_COMMAND 0 +#endif + +/* + gcdDUMP_FRAME_TGA + + When set to a value other than 0, a dump of the frame specified by the value, + will be done into frame.tga. Frame count starts from 1. + */ +#ifndef gcdDUMP_FRAME_TGA +#define gcdDUMP_FRAME_TGA 0 +#endif +/* + gcdNULL_DRIVER + + Set to 1 for infinite speed hardware. + Set to 2 for bypassing the HAL. + Set to 3 for bypassing the drivers. +*/ +#ifndef gcdNULL_DRIVER +# define gcdNULL_DRIVER 0 +#endif + +/* + gcdENABLE_TIMEOUT_DETECTION + + Enable timeout detection. +*/ +#ifndef gcdENABLE_TIMEOUT_DETECTION +# define gcdENABLE_TIMEOUT_DETECTION 0 +#endif + +/* + gcdCMD_BUFFER_SIZE + + Number of bytes in a command buffer. +*/ +#ifndef gcdCMD_BUFFER_SIZE +# define gcdCMD_BUFFER_SIZE (128 << 10) +#endif + +/* + gcdCMD_BUFFERS + + Number of command buffers to use per client. +*/ +#ifndef gcdCMD_BUFFERS +# define gcdCMD_BUFFERS 2 +#endif + +/* + gcdMAX_CMD_BUFFERS + + Maximum number of command buffers to use per client. +*/ +#ifndef gcdMAX_CMD_BUFFERS +# define gcdMAX_CMD_BUFFERS 8 +#endif + +/* + gcdCOMMAND_QUEUES + + Number of command queues in the kernel. +*/ +#ifndef gcdCOMMAND_QUEUES +# define gcdCOMMAND_QUEUES 2 +#endif + +/* + gcdPOWER_CONTROL_DELAY + + The delay in milliseconds required to wait until the GPU has woke up + from a suspend or power-down state. This is system dependent because + the bus clock also needs to stabalize. +*/ +#ifndef gcdPOWER_CONTROL_DELAY +# define gcdPOWER_CONTROL_DELAY 0 +#endif + +/* + gcdMMU_SIZE + + Size of the MMU page table in bytes. Each 4 bytes can hold 4kB worth of + virtual data. +*/ +#ifndef gcdMMU_SIZE +# define gcdMMU_SIZE (128 << 10) +#endif + +/* + gcdSECURE_USER + + Use logical addresses instead of physical addresses in user land. In + this case a hint table is created for both command buffers and context + buffers, and that hint table will be used to patch up those buffers in + the kernel when they are ready to submit. +*/ +#ifndef gcdSECURE_USER +# define gcdSECURE_USER 0 +#endif + +/* + gcdSECURE_CACHE_SLOTS + + Number of slots in the logical to DMA address cache table. Each time a + logical address needs to be translated into a DMA address for the GPU, + this cache will be walked. The replacement scheme is LRU. +*/ +#ifndef gcdSECURE_CACHE_SLOTS +# define gcdSECURE_CACHE_SLOTS 1024 +#endif + +/* + gcdSECURE_CACHE_METHOD + + Replacement scheme used for Secure Cache. The following options are + available: + + gcdSECURE_CACHE_LRU + A standard LRU cache. + + gcdSECURE_CACHE_LINEAR + A linear walker with the idea that an application will always + render the scene in a similar way, so the next entry in the + cache should be a hit most of the time. + + gcdSECURE_CACHE_HASH + A 256-entry hash table. + + gcdSECURE_CACHE_TABLE + A simple cache but with potential of a lot of cache replacement. +*/ +#ifndef gcdSECURE_CACHE_METHOD +# define gcdSECURE_CACHE_METHOD gcdSECURE_CACHE_HASH +#endif + +/* + gcdREGISTER_ACCESS_FROM_USER + + Set to 1 to allow IOCTL calls to get through from user land. This + should only be in debug or development drops. +*/ +#ifndef gcdREGISTER_ACCESS_FROM_USER +# define gcdREGISTER_ACCESS_FROM_USER 1 +#endif + +/* + gcdHEAP_SIZE + + Set the allocation size for the internal heaps. Each time a heap is + full, a new heap will be allocated with this minmimum amount of bytes. + The bigger this size, the fewer heaps there are to allocate, the better + the performance. However, heaps won't be freed until they are + completely free, so there might be some more memory waste if the size is + too big. +*/ +#ifndef gcdHEAP_SIZE +# define gcdHEAP_SIZE (64 << 10) +#endif + +/* + gcdPOWER_MANAGEMENT + + This define enables the power management code. +*/ +#ifndef gcdPOWER_MANAGEMENT +# define gcdPOWER_MANAGEMENT 1 +#endif + +/* + gcdFPGA_BUILD + + This define enables work arounds for FPGA images. +*/ +#ifndef gcdFPGA_BUILD +# define gcdFPGA_BUILD 0 +#endif + +/* + gcdGPU_TIMEOUT + + This define specified the number of milliseconds the system will wait + before it broadcasts the GPU is stuck. In other words, it will define + the timeout of any operation that needs to wait for the GPU. + + If the value is 0, no timeout will be checked for. +*/ +#ifndef gcdGPU_TIMEOUT +# if gcdFPGA_BUILD +# define gcdGPU_TIMEOUT 0 +# else +# define gcdGPU_TIMEOUT (2000 * 5) +# endif +#endif + +/* + gcdGPU_ADVANCETIMER + + it is advance timer. +*/ +#ifndef gcdGPU_ADVANCETIMER +# define gcdGPU_ADVANCETIMER 250 +#endif + +/* + gcdSTATIC_LINK + + This define disalbes static linking; +*/ +#ifndef gcdSTATIC_LINK +# define gcdSTATIC_LINK 0 +#endif + +/* + gcdUSE_NEW_HEAP + + Setting this define to 1 enables new heap. +*/ +#ifndef gcdUSE_NEW_HEAP +# define gcdUSE_NEW_HEAP 0 +#endif + +/* + gcdCMD_NO_2D_CONTEXT + + This define enables no-context 2D command buffer. +*/ +#ifndef gcdCMD_NO_2D_CONTEXT +# define gcdCMD_NO_2D_CONTEXT 1 +#endif + +/* + gcdENABLE_BANK_ALIGNMENT + + When enabled, video memory is allocated bank aligned. The vendor can modify + _GetSurfaceBankAlignment() and gcoSURF_GetBankOffsetBytes() to define how + different types of allocations are bank and channel aligned. + When disabled (default), no bank alignment is done. +*/ +#ifndef gcdENABLE_BANK_ALIGNMENT +# define gcdENABLE_BANK_ALIGNMENT 0 +#endif + +/* + gcdBANK_BIT_START + + Specifies the start bit of the bank (inclusive). +*/ +#ifndef gcdBANK_BIT_START +# define gcdBANK_BIT_START 12 +#endif + +/* + gcdBANK_BIT_END + + Specifies the end bit of the bank (inclusive). +*/ +#ifndef gcdBANK_BIT_END +# define gcdBANK_BIT_END 14 +#endif + +/* + gcdBANK_CHANNEL_BIT + + When set, video memory when allocated bank aligned is allocated such that + render and depth buffer addresses alternate on the channel bit specified. + This option has an effect only when gcdENABLE_BANK_ALIGNMENT is enabled. + When disabled (default), no alteration is done. +*/ +#ifndef gcdBANK_CHANNEL_BIT +# define gcdBANK_CHANNEL_BIT 7 +#endif + +/* + gcdDYNAMIC_SPEED + + When non-zero, it informs the kernel driver to use the speed throttling + broadcasting functions to inform the system the GPU should be spet up or + slowed down. It will send a broadcast for slowdown each "interval" + specified by this define in milliseconds + (gckOS_BroadcastCalibrateSpeed). +*/ +#ifndef gcdDYNAMIC_SPEED +# define gcdDYNAMIC_SPEED 2000 +#endif + +/* + gcdDYNAMIC_EVENT_THRESHOLD + + When non-zero, it specifies the maximum number of available events at + which the kernel driver will issue a broadcast to speed up the GPU + (gckOS_BroadcastHurry). +*/ +#ifndef gcdDYNAMIC_EVENT_THRESHOLD +# define gcdDYNAMIC_EVENT_THRESHOLD 5 +#endif + +/* + gcdENABLE_PROFILING + + Enable profiling macros. +*/ +#ifndef gcdENABLE_PROFILING +# define gcdENABLE_PROFILING 0 +#endif + +/* + gcdENABLE_128B_MERGE + + Enable 128B merge for the BUS control. +*/ +#ifndef gcdENABLE_128B_MERGE +# define gcdENABLE_128B_MERGE 0 +#endif + +/* + gcdFRAME_DB + + When non-zero, it specified the number of frames inside the frame + database. The frame DB will collect per-frame timestamps and hardware + counters. +*/ +#ifndef gcdFRAME_DB +# define gcdFRAME_DB 0 +# define gcdFRAME_DB_RESET 0 +# define gcdFRAME_DB_NAME "/var/log/frameDB.log" +#endif + +/* + gcdENABLE_VG + enable the 2D openVG +*/ + +#ifndef gcdENABLE_VG +# define gcdENABLE_VG 0 +#endif + +/* + gcdDYNAMIC_MAP_RESERVED_MEMORY + + When gcvPOOL_SYSTEM is constructed from RESERVED memory, + driver can map the whole reserved memory to kernel space + at the beginning, or just map a piece of memory when need + to access. + + Notice: + - It's only for the 2D openVG. For other cores, there is + _NO_ need to map reserved memory to kernel. + - It's meaningless when memory is allocated by + gckOS_AllocateContiguous, in that case, memory is always + mapped by system when allocated. +*/ +#ifndef gcdDYNAMIC_MAP_RESERVED_MEMORY +# define gcdDYNAMIC_MAP_RESERVED_MEMORY 1 +#endif + +/* + gcdPAGED_MEMORY_CACHEABLE + + When non-zero, paged memory will be cacheable. + + Normally, driver will detemines whether a video memory + is cacheable or not. When cacheable is not neccessary, + it will be writecombine. + + This option is only for those SOC which can't enable + writecombine without enabling cacheable. +*/ + +#ifndef gcdPAGED_MEMORY_CACHEABLE +# define gcdPAGED_MEMORY_CACHEABLE 0 +#endif + +/* + gcdNONPAGED_MEMORY_CACHEABLE + + When non-zero, non paged memory will be cacheable. +*/ + +#ifndef gcdNONPAGED_MEMORY_CACHEABLE +# define gcdNONPAGED_MEMORY_CACHEABLE 0 +#endif + +/* + gcdNONPAGED_MEMORY_BUFFERABLE + + When non-zero, non paged memory will be bufferable. + gcdNONPAGED_MEMORY_BUFFERABLE and gcdNONPAGED_MEMORY_CACHEABLE + can't be set 1 at same time +*/ + +#ifndef gcdNONPAGED_MEMORY_BUFFERABLE +# define gcdNONPAGED_MEMORY_BUFFERABLE 1 +#endif + +/* + gcdENABLE_INFINITE_SPEED_HW + enable the Infinte HW , this is for 2D openVG +*/ + +#ifndef gcdENABLE_INFINITE_SPEED_HW +# define gcdENABLE_INFINITE_SPEED_HW 0 +#endif + +/* + gcdENABLE_TS_DOUBLE_BUFFER + enable the TS double buffer, this is for 2D openVG +*/ + +#ifndef gcdENABLE_TS_DOUBLE_BUFFER +# define gcdENABLE_TS_DOUBLE_BUFFER 1 +#endif + +/* + gcd6000_SUPPORT + + Temporary define to enable/disable 6000 support. + */ +#ifndef gcd6000_SUPPORT +# define gcd6000_SUPPORT 0 +#endif + +/* + gcdPOWEROFF_TIMEOUT + + When non-zero, GPU will power off automatically from + idle state, and gcdPOWEROFF_TIMEOUT is also the default + timeout in milliseconds. + */ + +#ifndef gcdPOWEROFF_TIMEOUT +# define gcdPOWEROFF_TIMEOUT 300 +#endif + +/* + gcdUSE_VIDMEM_PER_PID +*/ +#ifndef gcdUSE_VIDMEM_PER_PID +# define gcdUSE_VIDMEM_PER_PID 0 +#endif + +/* + QNX_SINGLE_THREADED_DEBUGGING +*/ +#ifndef QNX_SINGLE_THREADED_DEBUGGING +# define QNX_SINGLE_THREADED_DEBUGGING 0 +#endif + +/* + gcdENABLE_RECOVERY + + This define enables the recovery code. +*/ +#ifndef gcdENABLE_RECOVERY +# define gcdENABLE_RECOVERY 1 +#endif + +/* + gcdRENDER_THREADS + + Number of render threads. Make it zero, and there will be no render + threads. +*/ +#ifndef gcdRENDER_THREADS +# define gcdRENDER_THREADS 0 +#endif + +/* + gcdSMP + + This define enables SMP support. + + Currently, it only works on Linux/Android, + Kbuild will config it according to whether + CONFIG_SMP is set. + +*/ +#ifndef gcdSMP +# define gcdSMP 0 +#endif + +/* + gcdSUPPORT_SWAP_RECTANGLE + + Support swap with a specific rectangle. + + Set the rectangle with eglSetSwapRectangleANDROID api. +*/ +#ifndef gcdSUPPORT_SWAP_RECTANGLE +# define gcdSUPPORT_SWAP_RECTANGLE 0 +#endif + +/* + gcdDEFER_RESOLVES + + Support deferred resolves for 3D apps. +*/ +#ifndef gcdDEFER_RESOLVES +# define gcdDEFER_RESOLVES 0 +#endif + +/* + gcdCOPYBLT_OPTIMIZATION + + Combine dirty areas resulting from Android's copyBlt. +*/ +#ifndef gcdCOPYBLT_OPTIMIZATION +# define gcdCOPYBLT_OPTIMIZATION 0 +#endif + +/* + gcdGPU_LINEAR_BUFFER_ENABLED + + Use linear buffer for GPU apps so HWC can do 2D composition. +*/ +#ifndef gcdGPU_LINEAR_BUFFER_ENABLED +# define gcdGPU_LINEAR_BUFFER_ENABLED 0 +#endif + +/* + gcdSHARED_RESOLVE_BUFFER_ENABLED + + Use shared resolve buffer for all app buffers. +*/ +#ifndef gcdSHARED_RESOLVE_BUFFER_ENABLED +# define gcdSHARED_RESOLVE_BUFFER_ENABLED 0 +#endif + +/* + gcdUSE_TRIANGLE_STRIP_PATCH + */ +#ifndef gcdUSE_TRIANGLE_STRIP_PATCH +# define gcdUSE_TRIANGLE_STRIP_PATCH 1 +#endif + +/* + gcdENABLE_OUTER_CACHE_PATCH + + Enable the outer cache patch. +*/ +#ifndef gcdENABLE_OUTER_CACHE_PATCH +# define gcdENABLE_OUTER_CACHE_PATCH 0 +#endif + +#ifndef gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST +# define gcdANDROID_UNALIGNED_LINEAR_COMPOSITION_ADJUST 0 +#endif + +#ifndef gcdSHARED_PAGETABLE +# define gcdSHARED_PAGETABLE 1 +#endif + +#ifndef gcdUSE_OPENCL +# define gcdUSE_OPENCL 0 +#endif + +/* + gcdBLOB_CACHE_ENABLED + When non-zero, Android blob cache extension will be enabled. + Otherwise, caching will be by-passed. + */ + +#ifndef gcdBLOB_CACHE_ENABLED +# define gcdBLOB_CACHE_ENABLED 0 +#endif + +/* + gcdSMALL_BLOCK_SIZE + + When non-zero, a part of VIDMEM will be reserved for requests + whose requesting size is less than gcdSMALL_BLOCK_SIZE. + + For Linux, it's the size of a page. If this requeset fallbacks + to gcvPOOL_CONTIGUOUS or gcvPOOL_VIRTUAL, memory will be wasted + because they allocate a page at least. + */ +#ifndef gcdSMALL_BLOCK_SIZE +# define gcdSMALL_BLOCK_SIZE 4096 +# define gcdRATIO_FOR_SMALL_MEMORY 32 +#endif + +#endif /* __gc_hal_options_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_profiler.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_profiler.h new file mode 100644 index 0000000..ee4a2ce --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_profiler.h @@ -0,0 +1,1311 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + +#ifndef __gc_hal_profiler_h_ +#define __gc_hal_profiler_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define GLVERTEX_OBJECT 10 +#define GLVERTEX_OBJECT_BYTES 11 + +#define GLINDEX_OBJECT 20 +#define GLINDEX_OBJECT_BYTES 21 + +#define GLTEXTURE_OBJECT 30 +#define GLTEXTURE_OBJECT_BYTES 31 + +#if VIVANTE_PROFILER +#define gcmPROFILE_GC(Enum, Value) gcoPROFILER_Count(gcvNULL, Enum, Value) +#else +#define gcmPROFILE_GC(Enum, Value) do { } while (gcvFALSE) +#endif + +#ifndef gcdNEW_PROFILER_FILE +#define gcdNEW_PROFILER_FILE 1 +#endif + +/* OpenGL ES11 API IDs. */ +#define ES11_ACTIVETEXTURE 1 +#define ES11_ALPHAFUNC (ES11_ACTIVETEXTURE + 1) +#define ES11_ALPHAFUNCX (ES11_ALPHAFUNC + 1) +#define ES11_BINDBUFFER (ES11_ALPHAFUNCX + 1) +#define ES11_BINDTEXTURE (ES11_BINDBUFFER + 1) +#define ES11_BLENDFUNC (ES11_BINDTEXTURE + 1) +#define ES11_BUFFERDATA (ES11_BLENDFUNC + 1) +#define ES11_BUFFERSUBDATA (ES11_BUFFERDATA + 1) +#define ES11_CLEAR (ES11_BUFFERSUBDATA + 1) +#define ES11_CLEARCOLOR (ES11_CLEAR + 1) +#define ES11_CLEARCOLORX (ES11_CLEARCOLOR + 1) +#define ES11_CLEARDEPTHF (ES11_CLEARCOLORX + 1) +#define ES11_CLEARDEPTHX (ES11_CLEARDEPTHF + 1) +#define ES11_CLEARSTENCIL (ES11_CLEARDEPTHX + 1) +#define ES11_CLIENTACTIVETEXTURE (ES11_CLEARSTENCIL + 1) +#define ES11_CLIPPLANEF (ES11_CLIENTACTIVETEXTURE + 1) +#define ES11_CLIPPLANEX (ES11_CLIPPLANEF + 1) +#define ES11_COLOR4F (ES11_CLIPPLANEX + 1) +#define ES11_COLOR4UB (ES11_COLOR4F + 1) +#define ES11_COLOR4X (ES11_COLOR4UB + 1) +#define ES11_COLORMASK (ES11_COLOR4X + 1) +#define ES11_COLORPOINTER (ES11_COLORMASK + 1) +#define ES11_COMPRESSEDTEXIMAGE2D (ES11_COLORPOINTER + 1) +#define ES11_COMPRESSEDTEXSUBIMAGE2D (ES11_COMPRESSEDTEXIMAGE2D + 1) +#define ES11_COPYTEXIMAGE2D (ES11_COMPRESSEDTEXSUBIMAGE2D + 1) +#define ES11_COPYTEXSUBIMAGE2D (ES11_COPYTEXIMAGE2D + 1) +#define ES11_CULLFACE (ES11_COPYTEXSUBIMAGE2D + 1) +#define ES11_DELETEBUFFERS (ES11_CULLFACE + 1) +#define ES11_DELETETEXTURES (ES11_DELETEBUFFERS + 1) +#define ES11_DEPTHFUNC (ES11_DELETETEXTURES + 1) +#define ES11_DEPTHMASK (ES11_DEPTHFUNC + 1) +#define ES11_DEPTHRANGEF (ES11_DEPTHMASK + 1) +#define ES11_DEPTHRANGEX (ES11_DEPTHRANGEF + 1) +#define ES11_DISABLE (ES11_DEPTHRANGEX + 1) +#define ES11_DISABLECLIENTSTATE (ES11_DISABLE + 1) +#define ES11_DRAWARRAYS (ES11_DISABLECLIENTSTATE + 1) +#define ES11_DRAWELEMENTS (ES11_DRAWARRAYS + 1) +#define ES11_ENABLE (ES11_DRAWELEMENTS + 1) +#define ES11_ENABLECLIENTSTATE (ES11_ENABLE + 1) +#define ES11_FINISH (ES11_ENABLECLIENTSTATE + 1) +#define ES11_FLUSH (ES11_FINISH + 1) +#define ES11_FOGF (ES11_FLUSH + 1) +#define ES11_FOGFV (ES11_FOGF + 1) +#define ES11_FOGX (ES11_FOGFV + 1) +#define ES11_FOGXV (ES11_FOGX + 1) +#define ES11_FRONTFACE (ES11_FOGXV + 1) +#define ES11_FRUSTUMF (ES11_FRONTFACE + 1) +#define ES11_FRUSTUMX (ES11_FRUSTUMF + 1) +#define ES11_GENBUFFERS (ES11_FRUSTUMX + 1) +#define ES11_GENTEXTURES (ES11_GENBUFFERS + 1) +#define ES11_GETBOOLEANV (ES11_GENTEXTURES + 1) +#define ES11_GETBUFFERPARAMETERIV (ES11_GETBOOLEANV + 1) +#define ES11_GETCLIPPLANEF (ES11_GETBUFFERPARAMETERIV + 1) +#define ES11_GETCLIPPLANEX (ES11_GETCLIPPLANEF + 1) +#define ES11_GETERROR (ES11_GETCLIPPLANEX + 1) +#define ES11_GETFIXEDV (ES11_GETERROR + 1) +#define ES11_GETFLOATV (ES11_GETFIXEDV + 1) +#define ES11_GETINTEGERV (ES11_GETFLOATV + 1) +#define ES11_GETLIGHTFV (ES11_GETINTEGERV + 1) +#define ES11_GETLIGHTXV (ES11_GETLIGHTFV + 1) +#define ES11_GETMATERIALFV (ES11_GETLIGHTXV + 1) +#define ES11_GETMATERIALXV (ES11_GETMATERIALFV + 1) +#define ES11_GETPOINTERV (ES11_GETMATERIALXV + 1) +#define ES11_GETSTRING (ES11_GETPOINTERV + 1) +#define ES11_GETTEXENVFV (ES11_GETSTRING + 1) +#define ES11_GETTEXENVIV (ES11_GETTEXENVFV + 1) +#define ES11_GETTEXENVXV (ES11_GETTEXENVIV + 1) +#define ES11_GETTEXPARAMETERFV (ES11_GETTEXENVXV + 1) +#define ES11_GETTEXPARAMETERIV (ES11_GETTEXPARAMETERFV + 1) +#define ES11_GETTEXPARAMETERXV (ES11_GETTEXPARAMETERIV + 1) +#define ES11_HINT (ES11_GETTEXPARAMETERXV + 1) +#define ES11_ISBUFFER (ES11_HINT + 1) +#define ES11_ISENABLED (ES11_ISBUFFER + 1) +#define ES11_ISTEXTURE (ES11_ISENABLED + 1) +#define ES11_LIGHTF (ES11_ISTEXTURE + 1) +#define ES11_LIGHTFV (ES11_LIGHTF + 1) +#define ES11_LIGHTMODELF (ES11_LIGHTFV + 1) +#define ES11_LIGHTMODELFV (ES11_LIGHTMODELF + 1) +#define ES11_LIGHTMODELX (ES11_LIGHTMODELFV + 1) +#define ES11_LIGHTMODELXV (ES11_LIGHTMODELX + 1) +#define ES11_LIGHTX (ES11_LIGHTMODELXV + 1) +#define ES11_LIGHTXV (ES11_LIGHTX + 1) +#define ES11_LINEWIDTH (ES11_LIGHTXV + 1) +#define ES11_LINEWIDTHX (ES11_LINEWIDTH + 1) +#define ES11_LOADIDENTITY (ES11_LINEWIDTHX + 1) +#define ES11_LOADMATRIXF (ES11_LOADIDENTITY + 1) +#define ES11_LOADMATRIXX (ES11_LOADMATRIXF + 1) +#define ES11_LOGICOP (ES11_LOADMATRIXX + 1) +#define ES11_MATERIALF (ES11_LOGICOP + 1) +#define ES11_MATERIALFV (ES11_MATERIALF + 1) +#define ES11_MATERIALX (ES11_MATERIALFV + 1) +#define ES11_MATERIALXV (ES11_MATERIALX + 1) +#define ES11_MATRIXMODE (ES11_MATERIALXV + 1) +#define ES11_MULTITEXCOORD4F (ES11_MATRIXMODE + 1) +#define ES11_MULTITEXCOORD4X (ES11_MULTITEXCOORD4F + 1) +#define ES11_MULTMATRIXF (ES11_MULTITEXCOORD4X + 1) +#define ES11_MULTMATRIXX (ES11_MULTMATRIXF + 1) +#define ES11_NORMAL3F (ES11_MULTMATRIXX + 1) +#define ES11_NORMAL3X (ES11_NORMAL3F + 1) +#define ES11_NORMALPOINTER (ES11_NORMAL3X + 1) +#define ES11_ORTHOF (ES11_NORMALPOINTER + 1) +#define ES11_ORTHOX (ES11_ORTHOF + 1) +#define ES11_PIXELSTOREI (ES11_ORTHOX + 1) +#define ES11_POINTPARAMETERF (ES11_PIXELSTOREI + 1) +#define ES11_POINTPARAMETERFV (ES11_POINTPARAMETERF + 1) +#define ES11_POINTPARAMETERX (ES11_POINTPARAMETERFV + 1) +#define ES11_POINTPARAMETERXV (ES11_POINTPARAMETERX + 1) +#define ES11_POINTSIZE (ES11_POINTPARAMETERXV + 1) +#define ES11_POINTSIZEX (ES11_POINTSIZE + 1) +#define ES11_POLYGONOFFSET (ES11_POINTSIZEX + 1) +#define ES11_POLYGONOFFSETX (ES11_POLYGONOFFSET + 1) +#define ES11_POPMATRIX (ES11_POLYGONOFFSETX + 1) +#define ES11_PUSHMATRIX (ES11_POPMATRIX + 1) +#define ES11_READPIXELS (ES11_PUSHMATRIX + 1) +#define ES11_ROTATEF (ES11_READPIXELS + 1) +#define ES11_ROTATEX (ES11_ROTATEF + 1) +#define ES11_SAMPLECOVERAGE (ES11_ROTATEX + 1) +#define ES11_SAMPLECOVERAGEX (ES11_SAMPLECOVERAGE + 1) +#define ES11_SCALEF (ES11_SAMPLECOVERAGEX + 1) +#define ES11_SCALEX (ES11_SCALEF + 1) +#define ES11_SCISSOR (ES11_SCALEX + 1) +#define ES11_SHADEMODEL (ES11_SCISSOR + 1) +#define ES11_STENCILFUNC (ES11_SHADEMODEL + 1) +#define ES11_STENCILMASK (ES11_STENCILFUNC + 1) +#define ES11_STENCILOP (ES11_STENCILMASK + 1) +#define ES11_TEXCOORDPOINTER (ES11_STENCILOP + 1) +#define ES11_TEXENVF (ES11_TEXCOORDPOINTER + 1) +#define ES11_TEXENVFV (ES11_TEXENVF + 1) +#define ES11_TEXENVI (ES11_TEXENVFV + 1) +#define ES11_TEXENVIV (ES11_TEXENVI + 1) +#define ES11_TEXENVX (ES11_TEXENVIV + 1) +#define ES11_TEXENVXV (ES11_TEXENVX + 1) +#define ES11_TEXIMAGE2D (ES11_TEXENVXV + 1) +#define ES11_TEXPARAMETERF (ES11_TEXIMAGE2D + 1) +#define ES11_TEXPARAMETERFV (ES11_TEXPARAMETERF + 1) +#define ES11_TEXPARAMETERI (ES11_TEXPARAMETERFV + 1) +#define ES11_TEXPARAMETERIV (ES11_TEXPARAMETERI + 1) +#define ES11_TEXPARAMETERX (ES11_TEXPARAMETERIV + 1) +#define ES11_TEXPARAMETERXV (ES11_TEXPARAMETERX + 1) +#define ES11_TEXSUBIMAGE2D (ES11_TEXPARAMETERXV + 1) +#define ES11_TRANSLATEF (ES11_TEXSUBIMAGE2D + 1) +#define ES11_TRANSLATEX (ES11_TRANSLATEF + 1) +#define ES11_VERTEXPOINTER (ES11_TRANSLATEX + 1) +#define ES11_VIEWPORT (ES11_VERTEXPOINTER + 1) +#define ES11_BLENDEQUATIONOES (ES11_VIEWPORT + 1) +#define ES11_BLENDFUNCSEPERATEOES (ES11_BLENDEQUATIONOES + 1) +#define ES11_BLENDEQUATIONSEPARATEOES (ES11_BLENDFUNCSEPERATEOES + 1) +#define ES11_GLMAPBUFFEROES (ES11_BLENDEQUATIONSEPARATEOES + 1) +#define ES11_GLUNMAPBUFFEROES (ES11_GLMAPBUFFEROES + 1) +#define ES11_GLGETBUFFERPOINTERVOES (ES11_GLUNMAPBUFFEROES + 1) +#define ES11_CALLS (ES11_GLGETBUFFERPOINTERVOES + 1) +#define ES11_DRAWCALLS (ES11_CALLS + 1) +#define ES11_STATECHANGECALLS (ES11_DRAWCALLS + 1) +#define ES11_POINTCOUNT (ES11_STATECHANGECALLS + 1) +#define ES11_LINECOUNT (ES11_POINTCOUNT + 1) +#define ES11_TRIANGLECOUNT (ES11_LINECOUNT + 1) + +/* OpenGL ES2X API IDs. */ +#define ES20_ACTIVETEXTURE 1 +#define ES20_ATTACHSHADER (ES20_ACTIVETEXTURE + 1) +#define ES20_BINDATTRIBLOCATION (ES20_ATTACHSHADER + 1) +#define ES20_BINDBUFFER (ES20_BINDATTRIBLOCATION + 1) +#define ES20_BINDFRAMEBUFFER (ES20_BINDBUFFER + 1) +#define ES20_BINDRENDERBUFFER (ES20_BINDFRAMEBUFFER + 1) +#define ES20_BINDTEXTURE (ES20_BINDRENDERBUFFER + 1) +#define ES20_BLENDCOLOR (ES20_BINDTEXTURE + 1) +#define ES20_BLENDEQUATION (ES20_BLENDCOLOR + 1) +#define ES20_BLENDEQUATIONSEPARATE (ES20_BLENDEQUATION + 1) +#define ES20_BLENDFUNC (ES20_BLENDEQUATIONSEPARATE + 1) +#define ES20_BLENDFUNCSEPARATE (ES20_BLENDFUNC + 1) +#define ES20_BUFFERDATA (ES20_BLENDFUNCSEPARATE + 1) +#define ES20_BUFFERSUBDATA (ES20_BUFFERDATA + 1) +#define ES20_CHECKFRAMEBUFFERSTATUS (ES20_BUFFERSUBDATA + 1) +#define ES20_CLEAR (ES20_CHECKFRAMEBUFFERSTATUS + 1) +#define ES20_CLEARCOLOR (ES20_CLEAR + 1) +#define ES20_CLEARDEPTHF (ES20_CLEARCOLOR + 1) +#define ES20_CLEARSTENCIL (ES20_CLEARDEPTHF + 1) +#define ES20_COLORMASK (ES20_CLEARSTENCIL + 1) +#define ES20_COMPILESHADER (ES20_COLORMASK + 1) +#define ES20_COMPRESSEDTEXIMAGE2D (ES20_COMPILESHADER + 1) +#define ES20_COMPRESSEDTEXSUBIMAGE2D (ES20_COMPRESSEDTEXIMAGE2D + 1) +#define ES20_COPYTEXIMAGE2D (ES20_COMPRESSEDTEXSUBIMAGE2D + 1) +#define ES20_COPYTEXSUBIMAGE2D (ES20_COPYTEXIMAGE2D + 1) +#define ES20_CREATEPROGRAM (ES20_COPYTEXSUBIMAGE2D + 1) +#define ES20_CREATESHADER (ES20_CREATEPROGRAM + 1) +#define ES20_CULLFACE (ES20_CREATESHADER + 1) +#define ES20_DELETEBUFFERS (ES20_CULLFACE + 1) +#define ES20_DELETEFRAMEBUFFERS (ES20_DELETEBUFFERS + 1) +#define ES20_DELETEPROGRAM (ES20_DELETEFRAMEBUFFERS + 1) +#define ES20_DELETERENDERBUFFERS (ES20_DELETEPROGRAM + 1) +#define ES20_DELETESHADER (ES20_DELETERENDERBUFFERS + 1) +#define ES20_DELETETEXTURES (ES20_DELETESHADER + 1) +#define ES20_DEPTHFUNC (ES20_DELETETEXTURES + 1) +#define ES20_DEPTHMASK (ES20_DEPTHFUNC + 1) +#define ES20_DEPTHRANGEF (ES20_DEPTHMASK + 1) +#define ES20_DETACHSHADER (ES20_DEPTHRANGEF + 1) +#define ES20_DISABLE (ES20_DETACHSHADER + 1) +#define ES20_DISABLEVERTEXATTRIBARRAY (ES20_DISABLE + 1) +#define ES20_DRAWARRAYS (ES20_DISABLEVERTEXATTRIBARRAY + 1) +#define ES20_DRAWELEMENTS (ES20_DRAWARRAYS + 1) +#define ES20_ENABLE (ES20_DRAWELEMENTS + 1) +#define ES20_ENABLEVERTEXATTRIBARRAY (ES20_ENABLE + 1) +#define ES20_FINISH (ES20_ENABLEVERTEXATTRIBARRAY + 1) +#define ES20_FLUSH (ES20_FINISH + 1) +#define ES20_FRAMEBUFFERRENDERBUFFER (ES20_FLUSH + 1) +#define ES20_FRAMEBUFFERTEXTURE2D (ES20_FRAMEBUFFERRENDERBUFFER + 1) +#define ES20_FRONTFACE (ES20_FRAMEBUFFERTEXTURE2D + 1) +#define ES20_GENBUFFERS (ES20_FRONTFACE + 1) +#define ES20_GENERATEMIPMAP (ES20_GENBUFFERS + 1) +#define ES20_GENFRAMEBUFFERS (ES20_GENERATEMIPMAP + 1) +#define ES20_GENRENDERBUFFERS (ES20_GENFRAMEBUFFERS + 1) +#define ES20_GENTEXTURES (ES20_GENRENDERBUFFERS + 1) +#define ES20_GETACTIVEATTRIB (ES20_GENTEXTURES + 1) +#define ES20_GETACTIVEUNIFORM (ES20_GETACTIVEATTRIB + 1) +#define ES20_GETATTACHEDSHADERS (ES20_GETACTIVEUNIFORM + 1) +#define ES20_GETATTRIBLOCATION (ES20_GETATTACHEDSHADERS + 1) +#define ES20_GETBOOLEANV (ES20_GETATTRIBLOCATION + 1) +#define ES20_GETBUFFERPARAMETERIV (ES20_GETBOOLEANV + 1) +#define ES20_GETERROR (ES20_GETBUFFERPARAMETERIV + 1) +#define ES20_GETFLOATV (ES20_GETERROR + 1) +#define ES20_GETFRAMEBUFFERATTACHMENTPARAMETERIV (ES20_GETFLOATV + 1) +#define ES20_GETINTEGERV (ES20_GETFRAMEBUFFERATTACHMENTPARAMETERIV + 1) +#define ES20_GETPROGRAMIV (ES20_GETINTEGERV + 1) +#define ES20_GETPROGRAMINFOLOG (ES20_GETPROGRAMIV + 1) +#define ES20_GETRENDERBUFFERPARAMETERIV (ES20_GETPROGRAMINFOLOG + 1) +#define ES20_GETSHADERIV (ES20_GETRENDERBUFFERPARAMETERIV + 1) +#define ES20_GETSHADERINFOLOG (ES20_GETSHADERIV + 1) +#define ES20_GETSHADERPRECISIONFORMAT (ES20_GETSHADERINFOLOG + 1) +#define ES20_GETSHADERSOURCE (ES20_GETSHADERPRECISIONFORMAT + 1) +#define ES20_GETSTRING (ES20_GETSHADERSOURCE + 1) +#define ES20_GETTEXPARAMETERFV (ES20_GETSTRING + 1) +#define ES20_GETTEXPARAMETERIV (ES20_GETTEXPARAMETERFV + 1) +#define ES20_GETUNIFORMFV (ES20_GETTEXPARAMETERIV + 1) +#define ES20_GETUNIFORMIV (ES20_GETUNIFORMFV + 1) +#define ES20_GETUNIFORMLOCATION (ES20_GETUNIFORMIV + 1) +#define ES20_GETVERTEXATTRIBFV (ES20_GETUNIFORMLOCATION + 1) +#define ES20_GETVERTEXATTRIBIV (ES20_GETVERTEXATTRIBFV + 1) +#define ES20_GETVERTEXATTRIBPOINTERV (ES20_GETVERTEXATTRIBIV + 1) +#define ES20_HINT (ES20_GETVERTEXATTRIBPOINTERV + 1) +#define ES20_ISBUFFER (ES20_HINT + 1) +#define ES20_ISENABLED (ES20_ISBUFFER + 1) +#define ES20_ISFRAMEBUFFER (ES20_ISENABLED + 1) +#define ES20_ISPROGRAM (ES20_ISFRAMEBUFFER + 1) +#define ES20_ISRENDERBUFFER (ES20_ISPROGRAM + 1) +#define ES20_ISSHADER (ES20_ISRENDERBUFFER + 1) +#define ES20_ISTEXTURE (ES20_ISSHADER + 1) +#define ES20_LINEWIDTH (ES20_ISTEXTURE + 1) +#define ES20_LINKPROGRAM (ES20_LINEWIDTH + 1) +#define ES20_PIXELSTOREI (ES20_LINKPROGRAM + 1) +#define ES20_POLYGONOFFSET (ES20_PIXELSTOREI + 1) +#define ES20_READPIXELS (ES20_POLYGONOFFSET + 1) +#define ES20_RELEASESHADERCOMPILER (ES20_READPIXELS + 1) +#define ES20_RENDERBUFFERSTORAGE (ES20_RELEASESHADERCOMPILER + 1) +#define ES20_SAMPLECOVERAGE (ES20_RENDERBUFFERSTORAGE + 1) +#define ES20_SCISSOR (ES20_SAMPLECOVERAGE + 1) +#define ES20_SHADERBINARY (ES20_SCISSOR + 1) +#define ES20_SHADERSOURCE (ES20_SHADERBINARY + 1) +#define ES20_STENCILFUNC (ES20_SHADERSOURCE + 1) +#define ES20_STENCILFUNCSEPARATE (ES20_STENCILFUNC + 1) +#define ES20_STENCILMASK (ES20_STENCILFUNCSEPARATE + 1) +#define ES20_STENCILMASKSEPARATE (ES20_STENCILMASK + 1) +#define ES20_STENCILOP (ES20_STENCILMASKSEPARATE + 1) +#define ES20_STENCILOPSEPARATE (ES20_STENCILOP + 1) +#define ES20_TEXIMAGE2D (ES20_STENCILOPSEPARATE + 1) +#define ES20_TEXPARAMETERF (ES20_TEXIMAGE2D + 1) +#define ES20_TEXPARAMETERFV (ES20_TEXPARAMETERF + 1) +#define ES20_TEXPARAMETERI (ES20_TEXPARAMETERFV + 1) +#define ES20_TEXPARAMETERIV (ES20_TEXPARAMETERI + 1) +#define ES20_TEXSUBIMAGE2D (ES20_TEXPARAMETERIV + 1) +#define ES20_UNIFORM1F (ES20_TEXSUBIMAGE2D + 1) +#define ES20_UNIFORM1FV (ES20_UNIFORM1F + 1) +#define ES20_UNIFORM1I (ES20_UNIFORM1FV + 1) +#define ES20_UNIFORM1IV (ES20_UNIFORM1I + 1) +#define ES20_UNIFORM2F (ES20_UNIFORM1IV + 1) +#define ES20_UNIFORM2FV (ES20_UNIFORM2F + 1) +#define ES20_UNIFORM2I (ES20_UNIFORM2FV + 1) +#define ES20_UNIFORM2IV (ES20_UNIFORM2I + 1) +#define ES20_UNIFORM3F (ES20_UNIFORM2IV + 1) +#define ES20_UNIFORM3FV (ES20_UNIFORM3F + 1) +#define ES20_UNIFORM3I (ES20_UNIFORM3FV + 1) +#define ES20_UNIFORM3IV (ES20_UNIFORM3I + 1) +#define ES20_UNIFORM4F (ES20_UNIFORM3IV + 1) +#define ES20_UNIFORM4FV (ES20_UNIFORM4F + 1) +#define ES20_UNIFORM4I (ES20_UNIFORM4FV + 1) +#define ES20_UNIFORM4IV (ES20_UNIFORM4I + 1) +#define ES20_UNIFORMMATRIX2FV (ES20_UNIFORM4IV + 1) +#define ES20_UNIFORMMATRIX3FV (ES20_UNIFORMMATRIX2FV + 1) +#define ES20_UNIFORMMATRIX4FV (ES20_UNIFORMMATRIX3FV + 1) +#define ES20_USEPROGRAM (ES20_UNIFORMMATRIX4FV + 1) +#define ES20_VALIDATEPROGRAM (ES20_USEPROGRAM + 1) +#define ES20_VERTEXATTRIB1F (ES20_VALIDATEPROGRAM + 1) +#define ES20_VERTEXATTRIB1FV (ES20_VERTEXATTRIB1F + 1) +#define ES20_VERTEXATTRIB2F (ES20_VERTEXATTRIB1FV + 1) +#define ES20_VERTEXATTRIB2FV (ES20_VERTEXATTRIB2F + 1) +#define ES20_VERTEXATTRIB3F (ES20_VERTEXATTRIB2FV + 1) +#define ES20_VERTEXATTRIB3FV (ES20_VERTEXATTRIB3F + 1) +#define ES20_VERTEXATTRIB4F (ES20_VERTEXATTRIB3FV + 1) +#define ES20_VERTEXATTRIB4FV (ES20_VERTEXATTRIB4F + 1) +#define ES20_VERTEXATTRIBPOINTER (ES20_VERTEXATTRIB4FV + 1) +#define ES20_VIEWPORT (ES20_VERTEXATTRIBPOINTER + 1) +#define ES20_GETPROGRAMBINARYOES (ES20_VIEWPORT + 1) +#define ES20_PROGRAMBINARYOES (ES20_GETPROGRAMBINARYOES + 1) +#define ES20_TEXIMAGE3DOES (ES20_PROGRAMBINARYOES + 1) +#define ES20_TEXSUBIMAGE3DOES (ES20_TEXIMAGE3DOES + 1) +#define ES20_COPYSUBIMAGE3DOES (ES20_TEXSUBIMAGE3DOES + 1) +#define ES20_COMPRESSEDTEXIMAGE3DOES (ES20_COPYSUBIMAGE3DOES + 1) +#define ES20_COMPRESSEDTEXSUBIMAGE3DOES (ES20_COMPRESSEDTEXIMAGE3DOES + 1) +#define ES20_FRAMEBUFFERTEXTURE3DOES (ES20_COMPRESSEDTEXSUBIMAGE3DOES + 1) +#define ES20_BINDVERTEXARRAYOES (ES20_FRAMEBUFFERTEXTURE3DOES + 1) +#define ES20_GENVERTEXARRAYOES (ES20_BINDVERTEXARRAYOES + 1) +#define ES20_ISVERTEXARRAYOES (ES20_GENVERTEXARRAYOES + 1) +#define ES20_DELETEVERTEXARRAYOES (ES20_ISVERTEXARRAYOES + 1) +#define ES20_GLMAPBUFFEROES (ES20_DELETEVERTEXARRAYOES + 1) +#define ES20_GLUNMAPBUFFEROES (ES20_GLMAPBUFFEROES + 1) +#define ES20_GLGETBUFFERPOINTERVOES (ES20_GLUNMAPBUFFEROES + 1) +#define ES20_CALLS (ES20_GLGETBUFFERPOINTERVOES + 1) +#define ES20_DRAWCALLS (ES20_CALLS + 1) +#define ES20_STATECHANGECALLS (ES20_DRAWCALLS + 1) +#define ES20_POINTCOUNT (ES20_STATECHANGECALLS + 1) +#define ES20_LINECOUNT (ES20_POINTCOUNT + 1) +#define ES20_TRIANGLECOUNT (ES20_LINECOUNT + 1) + +/* OpenVG API IDs. */ +#define VG11_APPENDPATH 1 +#define VG11_APPENDPATHDATA (VG11_APPENDPATH + 1) +#define VG11_CHILDIMAGE (VG11_APPENDPATHDATA + 1) +#define VG11_CLEAR (VG11_CHILDIMAGE + 1) +#define VG11_CLEARGLYPH (VG11_CLEAR + 1) +#define VG11_CLEARIMAGE (VG11_CLEARGLYPH + 1) +#define VG11_CLEARPATH (VG11_CLEARIMAGE + 1) +#define VG11_COLORMATRIX (VG11_CLEARPATH + 1) +#define VG11_CONVOLVE (VG11_COLORMATRIX + 1) +#define VG11_COPYIMAGE (VG11_CONVOLVE + 1) +#define VG11_COPYMASK (VG11_COPYIMAGE + 1) +#define VG11_COPYPIXELS (VG11_COPYMASK + 1) +#define VG11_CREATEFONT (VG11_COPYPIXELS + 1) +#define VG11_CREATEIMAGE (VG11_CREATEFONT + 1) +#define VG11_CREATEMASKLAYER (VG11_CREATEIMAGE + 1) +#define VG11_CREATEPAINT (VG11_CREATEMASKLAYER + 1) +#define VG11_CREATEPATH (VG11_CREATEPAINT + 1) +#define VG11_DESTROYFONT (VG11_CREATEPATH + 1) +#define VG11_DESTROYIMAGE (VG11_DESTROYFONT + 1) +#define VG11_DESTROYMASKLAYER (VG11_DESTROYIMAGE + 1) +#define VG11_DESTROYPAINT (VG11_DESTROYMASKLAYER + 1) +#define VG11_DESTROYPATH (VG11_DESTROYPAINT + 1) +#define VG11_DRAWGLYPH (VG11_DESTROYPATH + 1) +#define VG11_DRAWGLYPHS (VG11_DRAWGLYPH + 1) +#define VG11_DRAWIMAGE (VG11_DRAWGLYPHS + 1) +#define VG11_DRAWPATH (VG11_DRAWIMAGE + 1) +#define VG11_FILLMASKLAYER (VG11_DRAWPATH + 1) +#define VG11_FINISH (VG11_FILLMASKLAYER + 1) +#define VG11_FLUSH (VG11_FINISH + 1) +#define VG11_GAUSSIANBLUR (VG11_FLUSH + 1) +#define VG11_GETCOLOR (VG11_GAUSSIANBLUR + 1) +#define VG11_GETERROR (VG11_GETCOLOR + 1) +#define VG11_GETF (VG11_GETERROR + 1) +#define VG11_GETFV (VG11_GETF + 1) +#define VG11_GETI (VG11_GETFV + 1) +#define VG11_GETIMAGESUBDATA (VG11_GETI + 1) +#define VG11_GETIV (VG11_GETIMAGESUBDATA + 1) +#define VG11_GETMATRIX (VG11_GETIV + 1) +#define VG11_GETPAINT (VG11_GETMATRIX + 1) +#define VG11_GETPARAMETERF (VG11_GETPAINT + 1) +#define VG11_GETPARAMETERFV (VG11_GETPARAMETERF + 1) +#define VG11_GETPARAMETERI (VG11_GETPARAMETERFV + 1) +#define VG11_GETPARAMETERIV (VG11_GETPARAMETERI + 1) +#define VG11_GETPARAMETERVECTORSIZE (VG11_GETPARAMETERIV + 1) +#define VG11_GETPARENT (VG11_GETPARAMETERVECTORSIZE + 1) +#define VG11_GETPATHCAPABILITIES (VG11_GETPARENT + 1) +#define VG11_GETPIXELS (VG11_GETPATHCAPABILITIES + 1) +#define VG11_GETSTRING (VG11_GETPIXELS + 1) +#define VG11_GETVECTORSIZE (VG11_GETSTRING + 1) +#define VG11_HARDWAREQUERY (VG11_GETVECTORSIZE + 1) +#define VG11_IMAGESUBDATA (VG11_HARDWAREQUERY + 1) +#define VG11_INTERPOLATEPATH (VG11_IMAGESUBDATA + 1) +#define VG11_LOADIDENTITY (VG11_INTERPOLATEPATH + 1) +#define VG11_LOADMATRIX (VG11_LOADIDENTITY + 1) +#define VG11_LOOKUP (VG11_LOADMATRIX + 1) +#define VG11_LOOKUPSINGLE (VG11_LOOKUP + 1) +#define VG11_MASK (VG11_LOOKUPSINGLE + 1) +#define VG11_MODIFYPATHCOORDS (VG11_MASK + 1) +#define VG11_MULTMATRIX (VG11_MODIFYPATHCOORDS + 1) +#define VG11_PAINTPATTERN (VG11_MULTMATRIX + 1) +#define VG11_PATHBOUNDS (VG11_PAINTPATTERN + 1) +#define VG11_PATHLENGTH (VG11_PATHBOUNDS + 1) +#define VG11_PATHTRANSFORMEDBOUNDS (VG11_PATHLENGTH + 1) +#define VG11_POINTALONGPATH (VG11_PATHTRANSFORMEDBOUNDS + 1) +#define VG11_READPIXELS (VG11_POINTALONGPATH + 1) +#define VG11_REMOVEPATHCAPABILITIES (VG11_READPIXELS + 1) +#define VG11_RENDERTOMASK (VG11_REMOVEPATHCAPABILITIES + 1) +#define VG11_ROTATE (VG11_RENDERTOMASK + 1) +#define VG11_SCALE (VG11_ROTATE + 1) +#define VG11_SEPARABLECONVOLVE (VG11_SCALE + 1) +#define VG11_SETCOLOR (VG11_SEPARABLECONVOLVE + 1) +#define VG11_SETF (VG11_SETCOLOR + 1) +#define VG11_SETFV (VG11_SETF + 1) +#define VG11_SETGLYPHTOIMAGE (VG11_SETFV + 1) +#define VG11_SETGLYPHTOPATH (VG11_SETGLYPHTOIMAGE + 1) +#define VG11_SETI (VG11_SETGLYPHTOPATH + 1) +#define VG11_SETIV (VG11_SETI + 1) +#define VG11_SETPAINT (VG11_SETIV + 1) +#define VG11_SETPARAMETERF (VG11_SETPAINT + 1) +#define VG11_SETPARAMETERFV (VG11_SETPARAMETERF + 1) +#define VG11_SETPARAMETERI (VG11_SETPARAMETERFV + 1) +#define VG11_SETPARAMETERIV (VG11_SETPARAMETERI + 1) +#define VG11_SETPIXELS (VG11_SETPARAMETERIV + 1) +#define VG11_SHEAR (VG11_SETPIXELS + 1) +#define VG11_TRANSFORMPATH (VG11_SHEAR + 1) +#define VG11_TRANSLATE (VG11_TRANSFORMPATH + 1) +#define VG11_WRITEPIXELS (VG11_TRANSLATE + 1) +#define VG11_CALLS (VG11_WRITEPIXELS + 1) +#define VG11_DRAWCALLS (VG11_CALLS + 1) +#define VG11_STATECHANGECALLS (VG11_DRAWCALLS + 1) +#define VG11_FILLCOUNT (VG11_STATECHANGECALLS + 1) +#define VG11_STROKECOUNT (VG11_FILLCOUNT + 1) +/* End of Driver API ID Definitions. */ + +/* HAL & MISC IDs. */ +#define HAL_VERTBUFNEWBYTEALLOC 1 +#define HAL_VERTBUFTOTALBYTEALLOC (HAL_VERTBUFNEWBYTEALLOC + 1) +#define HAL_VERTBUFNEWOBJALLOC (HAL_VERTBUFTOTALBYTEALLOC + 1) +#define HAL_VERTBUFTOTALOBJALLOC (HAL_VERTBUFNEWOBJALLOC + 1) +#define HAL_INDBUFNEWBYTEALLOC (HAL_VERTBUFTOTALOBJALLOC + 1) +#define HAL_INDBUFTOTALBYTEALLOC (HAL_INDBUFNEWBYTEALLOC + 1) +#define HAL_INDBUFNEWOBJALLOC (HAL_INDBUFTOTALBYTEALLOC + 1) +#define HAL_INDBUFTOTALOBJALLOC (HAL_INDBUFNEWOBJALLOC + 1) +#define HAL_TEXBUFNEWBYTEALLOC (HAL_INDBUFTOTALOBJALLOC + 1) +#define HAL_TEXBUFTOTALBYTEALLOC (HAL_TEXBUFNEWBYTEALLOC + 1) +#define HAL_TEXBUFNEWOBJALLOC (HAL_TEXBUFTOTALBYTEALLOC + 1) +#define HAL_TEXBUFTOTALOBJALLOC (HAL_TEXBUFNEWOBJALLOC + 1) + +#define GPU_CYCLES 1 +#define GPU_READ64BYTE (GPU_CYCLES + 1) +#define GPU_WRITE64BYTE (GPU_READ64BYTE + 1) + +#define VS_INSTCOUNT 1 +#define VS_BRANCHINSTCOUNT (VS_INSTCOUNT + 1) +#define VS_TEXLDINSTCOUNT (VS_BRANCHINSTCOUNT + 1) +#define VS_RENDEREDVERTCOUNT (VS_TEXLDINSTCOUNT + 1) + +#define PS_INSTCOUNT 1 +#define PS_BRANCHINSTCOUNT (PS_INSTCOUNT + 1) +#define PS_TEXLDINSTCOUNT (PS_BRANCHINSTCOUNT + 1) +#define PS_RENDEREDPIXCOUNT (PS_TEXLDINSTCOUNT + 1) + +#define PA_INVERTCOUNT 1 +#define PA_INPRIMCOUNT (PA_INVERTCOUNT + 1) +#define PA_OUTPRIMCOUNT (PA_INPRIMCOUNT + 1) +#define PA_DEPTHCLIPCOUNT (PA_OUTPRIMCOUNT + 1) +#define PA_TRIVIALREJCOUNT (PA_DEPTHCLIPCOUNT + 1) +#define PA_CULLCOUNT (PA_TRIVIALREJCOUNT + 1) + +#define SE_TRIANGLECOUNT 1 +#define SE_LINECOUNT (SE_TRIANGLECOUNT + 1) + +#define RA_VALIDPIXCOUNT 1 +#define RA_TOTALQUADCOUNT (RA_VALIDPIXCOUNT + 1) +#define RA_VALIDQUADCOUNTEZ (RA_TOTALQUADCOUNT + 1) +#define RA_TOTALPRIMCOUNT (RA_VALIDQUADCOUNTEZ + 1) +#define RA_PIPECACHEMISSCOUNT (RA_TOTALPRIMCOUNT + 1) +#define RA_PREFCACHEMISSCOUNT (RA_PIPECACHEMISSCOUNT + 1) +#define RA_EEZCULLCOUNT (RA_PREFCACHEMISSCOUNT + 1) + +#define TX_TOTBILINEARREQ 1 +#define TX_TOTTRILINEARREQ (TX_TOTBILINEARREQ + 1) +#define TX_TOTDISCARDTEXREQ (TX_TOTTRILINEARREQ + 1) +#define TX_TOTTEXREQ (TX_TOTDISCARDTEXREQ + 1) +#define TX_MEMREADCOUNT (TX_TOTTEXREQ + 1) +#define TX_MEMREADIN8BCOUNT (TX_MEMREADCOUNT + 1) +#define TX_CACHEMISSCOUNT (TX_MEMREADIN8BCOUNT + 1) +#define TX_CACHEHITTEXELCOUNT (TX_CACHEMISSCOUNT + 1) +#define TX_CACHEMISSTEXELCOUNT (TX_CACHEHITTEXELCOUNT + 1) + +#define PE_KILLEDBYCOLOR 1 +#define PE_KILLEDBYDEPTH (PE_KILLEDBYCOLOR + 1) +#define PE_DRAWNBYCOLOR (PE_KILLEDBYDEPTH + 1) +#define PE_DRAWNBYDEPTH (PE_DRAWNBYCOLOR + 1) + +#define MC_READREQ8BPIPE 1 +#define MC_READREQ8BIP (MC_READREQ8BPIPE + 1) +#define MC_WRITEREQ8BPIPE (MC_READREQ8BIP + 1) + +#define AXI_READREQSTALLED 1 +#define AXI_WRITEREQSTALLED (AXI_READREQSTALLED + 1) +#define AXI_WRITEDATASTALLED (AXI_WRITEREQSTALLED + 1) + +#define PVS_INSTRCOUNT 1 +#define PVS_ALUINSTRCOUNT (PVS_INSTRCOUNT + 1) +#define PVS_TEXINSTRCOUNT (PVS_ALUINSTRCOUNT + 1) +#define PVS_ATTRIBCOUNT (PVS_TEXINSTRCOUNT + 1) +#define PVS_UNIFORMCOUNT (PVS_ATTRIBCOUNT + 1) +#define PVS_FUNCTIONCOUNT (PVS_UNIFORMCOUNT + 1) + +#define PPS_INSTRCOUNT 1 +#define PPS_ALUINSTRCOUNT (PPS_INSTRCOUNT + 1) +#define PPS_TEXINSTRCOUNT (PPS_ALUINSTRCOUNT + 1) +#define PPS_ATTRIBCOUNT (PPS_TEXINSTRCOUNT + 1) +#define PPS_UNIFORMCOUNT (PPS_ATTRIBCOUNT + 1) +#define PPS_FUNCTIONCOUNT (PPS_UNIFORMCOUNT + 1) +/* End of MISC Counter IDs. */ + +#ifdef gcdNEW_PROFILER_FILE + +/* Category Constants. */ +#define VPHEADER 0x010000 +#define VPG_INFO 0x020000 +#define VPG_TIME 0x030000 +#define VPG_MEM 0x040000 +#define VPG_ES11 0x050000 +#define VPG_ES20 0x060000 +#define VPG_VG11 0x070000 +#define VPG_HAL 0x080000 +#define VPG_HW 0x090000 +#define VPG_GPU 0x0a0000 +#define VPG_VS 0x0b0000 +#define VPG_PS 0x0c0000 +#define VPG_PA 0x0d0000 +#define VPG_SETUP 0x0e0000 +#define VPG_RA 0x0f0000 +#define VPG_TX 0x100000 +#define VPG_PE 0x110000 +#define VPG_MC 0x120000 +#define VPG_AXI 0x130000 +#define VPG_PROG 0x140000 +#define VPG_PVS 0x150000 +#define VPG_PPS 0x160000 +#define VPG_FRAME 0x170000 +#define VPG_END 0xff0000 + +/* Info. */ +#define VPC_INFOCOMPANY (VPG_INFO + 1) +#define VPC_INFOVERSION (VPC_INFOCOMPANY + 1) +#define VPC_INFORENDERER (VPC_INFOVERSION + 1) +#define VPC_INFOREVISION (VPC_INFORENDERER + 1) +#define VPC_INFODRIVER (VPC_INFOREVISION + 1) +#define VPC_INFODRIVERMODE (VPC_INFODRIVER + 1) +#define VPC_INFOSCREENSIZE (VPC_INFODRIVERMODE + 1) + +/* Counter Constants. */ +#define VPC_ELAPSETIME (VPG_TIME + 1) +#define VPC_CPUTIME (VPC_ELAPSETIME + 1) + +#define VPC_MEMMAXRES (VPG_MEM + 1) +#define VPC_MEMSHARED (VPC_MEMMAXRES + 1) +#define VPC_MEMUNSHAREDDATA (VPC_MEMSHARED + 1) +#define VPC_MEMUNSHAREDSTACK (VPC_MEMUNSHAREDDATA + 1) + +/* OpenGL ES11 Counters. */ +#define VPC_ES11ACTIVETEXTURE (VPG_ES11 + ES11_ACTIVETEXTURE) +#define VPC_ES11ALPHAFUNC (VPG_ES11 + ES11_ALPHAFUNC) +#define VPC_ES11ALPHAFUNCX (VPG_ES11 + ES11_ALPHAFUNCX) +#define VPC_ES11BINDBUFFER (VPG_ES11 + ES11_BINDBUFFER) +#define VPC_ES11BINDTEXTURE (VPG_ES11 + ES11_BINDTEXTURE) +#define VPC_ES11BLENDFUNC (VPG_ES11 + ES11_BLENDFUNC) +#define VPC_ES11BUFFERDATA (VPG_ES11 + ES11_BUFFERDATA) +#define VPC_ES11BUFFERSUBDATA (VPG_ES11 + ES11_BUFFERSUBDATA) +#define VPC_ES11CLEAR (VPG_ES11 + ES11_CLEAR) +#define VPC_ES11CLEARCOLOR (VPG_ES11 + ES11_CLEARCOLOR) +#define VPC_ES11CLEARCOLORX (VPG_ES11 + ES11_CLEARCOLORX) +#define VPC_ES11CLEARDEPTHF (VPG_ES11 + ES11_CLEARDEPTHF) +#define VPC_ES11CLEARDEPTHX (VPG_ES11 + ES11_CLEARDEPTHX) +#define VPC_ES11CLEARSTENCIL (VPG_ES11 + ES11_CLEARSTENCIL) +#define VPC_ES11CLIENTACTIVETEXTURE (VPG_ES11 + ES11_CLIENTACTIVETEXTURE) +#define VPC_ES11CLIPPLANEF (VPG_ES11 + ES11_CLIPPLANEF) +#define VPC_ES11CLIPPLANEX (VPG_ES11 + ES11_CLIPPLANEX) +#define VPC_ES11COLOR4F (VPG_ES11 + ES11_COLOR4F) +#define VPC_ES11COLOR4UB (VPG_ES11 + ES11_COLOR4UB) +#define VPC_ES11COLOR4X (VPG_ES11 + ES11_COLOR4X) +#define VPC_ES11COLORMASK (VPG_ES11 + ES11_COLORMASK) +#define VPC_ES11COLORPOINTER (VPG_ES11 + ES11_COLORPOINTER) +#define VPC_ES11COMPRESSEDTEXIMAGE2D (VPG_ES11 + ES11_COMPRESSEDTEXIMAGE2D) +#define VPC_ES11COMPRESSEDTEXSUBIMAGE2D (VPG_ES11 + ES11_COMPRESSEDTEXSUBIMAGE2D) +#define VPC_ES11COPYTEXIMAGE2D (VPG_ES11 + ES11_COPYTEXIMAGE2D) +#define VPC_ES11COPYTEXSUBIMAGE2D (VPG_ES11 + ES11_COPYTEXSUBIMAGE2D) +#define VPC_ES11CULLFACE (VPG_ES11 + ES11_CULLFACE) +#define VPC_ES11DELETEBUFFERS (VPG_ES11 + ES11_DELETEBUFFERS) +#define VPC_ES11DELETETEXTURES (VPG_ES11 + ES11_DELETETEXTURES) +#define VPC_ES11DEPTHFUNC (VPG_ES11 + ES11_DEPTHFUNC) +#define VPC_ES11DEPTHMASK (VPG_ES11 + ES11_DEPTHMASK) +#define VPC_ES11DEPTHRANGEF (VPG_ES11 + ES11_DEPTHRANGEF) +#define VPC_ES11DEPTHRANGEX (VPG_ES11 + ES11_DEPTHRANGEX) +#define VPC_ES11DISABLE (VPG_ES11 + ES11_DISABLE) +#define VPC_ES11DISABLECLIENTSTATE (VPG_ES11 + ES11_DISABLECLIENTSTATE) +#define VPC_ES11DRAWARRAYS (VPG_ES11 + ES11_DRAWARRAYS) +#define VPC_ES11DRAWELEMENTS (VPG_ES11 + ES11_DRAWELEMENTS) +#define VPC_ES11ENABLE (VPG_ES11 + ES11_ENABLE) +#define VPC_ES11ENABLECLIENTSTATE (VPG_ES11 + ES11_ENABLECLIENTSTATE) +#define VPC_ES11FINISH (VPG_ES11 + ES11_FINISH) +#define VPC_ES11FLUSH (VPG_ES11 + ES11_FLUSH) +#define VPC_ES11FOGF (VPG_ES11 + ES11_FOGF) +#define VPC_ES11FOGFV (VPG_ES11 + ES11_FOGFV) +#define VPC_ES11FOGX (VPG_ES11 + ES11_FOGX) +#define VPC_ES11FOGXV (VPG_ES11 + ES11_FOGXV) +#define VPC_ES11FRONTFACE (VPG_ES11 + ES11_FRONTFACE) +#define VPC_ES11FRUSTUMF (VPG_ES11 + ES11_FRUSTUMF) +#define VPC_ES11FRUSTUMX (VPG_ES11 + ES11_FRUSTUMX) +#define VPC_ES11GENBUFFERS (VPG_ES11 + ES11_GENBUFFERS) +#define VPC_ES11GENTEXTURES (VPG_ES11 + ES11_GENTEXTURES) +#define VPC_ES11GETBOOLEANV (VPG_ES11 + ES11_GETBOOLEANV) +#define VPC_ES11GETBUFFERPARAMETERIV (VPG_ES11 + ES11_GETBUFFERPARAMETERIV) +#define VPC_ES11GETCLIPPLANEF (VPG_ES11 + ES11_GETCLIPPLANEF) +#define VPC_ES11GETCLIPPLANEX (VPG_ES11 + ES11_GETCLIPPLANEX) +#define VPC_ES11GETERROR (VPG_ES11 + ES11_GETERROR) +#define VPC_ES11GETFIXEDV (VPG_ES11 + ES11_GETFIXEDV) +#define VPC_ES11GETFLOATV (VPG_ES11 + ES11_GETFLOATV) +#define VPC_ES11GETINTEGERV (VPG_ES11 + ES11_GETINTEGERV) +#define VPC_ES11GETLIGHTFV (VPG_ES11 + ES11_GETLIGHTFV) +#define VPC_ES11GETLIGHTXV (VPG_ES11 + ES11_GETLIGHTXV) +#define VPC_ES11GETMATERIALFV (VPG_ES11 + ES11_GETMATERIALFV) +#define VPC_ES11GETMATERIALXV (VPG_ES11 + ES11_GETMATERIALXV) +#define VPC_ES11GETPOINTERV (VPG_ES11 + ES11_GETPOINTERV) +#define VPC_ES11GETSTRING (VPG_ES11 + ES11_GETSTRING) +#define VPC_ES11GETTEXENVFV (VPG_ES11 + ES11_GETTEXENVFV) +#define VPC_ES11GETTEXENVIV (VPG_ES11 + ES11_GETTEXENVIV) +#define VPC_ES11GETTEXENVXV (VPG_ES11 + ES11_GETTEXENVXV) +#define VPC_ES11GETTEXPARAMETERFV (VPG_ES11 + ES11_GETTEXPARAMETERFV) +#define VPC_ES11GETTEXPARAMETERIV (VPG_ES11 + ES11_GETTEXPARAMETERIV) +#define VPC_ES11GETTEXPARAMETERXV (VPG_ES11 + ES11_GETTEXPARAMETERXV) +#define VPC_ES11HINT (VPG_ES11 + ES11_HINT) +#define VPC_ES11ISBUFFER (VPG_ES11 + ES11_ISBUFFER) +#define VPC_ES11ISENABLED (VPG_ES11 + ES11_ISENABLED) +#define VPC_ES11ISTEXTURE (VPG_ES11 + ES11_ISTEXTURE) +#define VPC_ES11LIGHTF (VPG_ES11 + ES11_LIGHTF) +#define VPC_ES11LIGHTFV (VPG_ES11 + ES11_LIGHTFV) +#define VPC_ES11LIGHTMODELF (VPG_ES11 + ES11_LIGHTMODELF) +#define VPC_ES11LIGHTMODELFV (VPG_ES11 + ES11_LIGHTMODELFV) +#define VPC_ES11LIGHTMODELX (VPG_ES11 + ES11_LIGHTMODELX) +#define VPC_ES11LIGHTMODELXV (VPG_ES11 + ES11_LIGHTMODELXV) +#define VPC_ES11LIGHTX (VPG_ES11 + ES11_LIGHTX) +#define VPC_ES11LIGHTXV (VPG_ES11 + ES11_LIGHTXV) +#define VPC_ES11LINEWIDTH (VPG_ES11 + ES11_LINEWIDTH) +#define VPC_ES11LINEWIDTHX (VPG_ES11 + ES11_LINEWIDTHX) +#define VPC_ES11LOADIDENTITY (VPG_ES11 + ES11_LOADIDENTITY) +#define VPC_ES11LOADMATRIXF (VPG_ES11 + ES11_LOADMATRIXF) +#define VPC_ES11LOADMATRIXX (VPG_ES11 + ES11_LOADMATRIXX) +#define VPC_ES11LOGICOP (VPG_ES11 + ES11_LOGICOP) +#define VPC_ES11MATERIALF (VPG_ES11 + ES11_MATERIALF) +#define VPC_ES11MATERIALFV (VPG_ES11 + ES11_MATERIALFV) +#define VPC_ES11MATERIALX (VPG_ES11 + ES11_MATERIALX) +#define VPC_ES11MATERIALXV (VPG_ES11 + ES11_MATERIALXV) +#define VPC_ES11MATRIXMODE (VPG_ES11 + ES11_MATRIXMODE) +#define VPC_ES11MULTITEXCOORD4F (VPG_ES11 + ES11_MULTITEXCOORD4F) +#define VPC_ES11MULTITEXCOORD4X (VPG_ES11 + ES11_MULTITEXCOORD4X) +#define VPC_ES11MULTMATRIXF (VPG_ES11 + ES11_MULTMATRIXF) +#define VPC_ES11MULTMATRIXX (VPG_ES11 + ES11_MULTMATRIXX) +#define VPC_ES11NORMAL3F (VPG_ES11 + ES11_NORMAL3F) +#define VPC_ES11NORMAL3X (VPG_ES11 + ES11_NORMAL3X) +#define VPC_ES11NORMALPOINTER (VPG_ES11 + ES11_NORMALPOINTER) +#define VPC_ES11ORTHOF (VPG_ES11 + ES11_ORTHOF) +#define VPC_ES11ORTHOX (VPG_ES11 + ES11_ORTHOX) +#define VPC_ES11PIXELSTOREI (VPG_ES11 + ES11_PIXELSTOREI) +#define VPC_ES11POINTPARAMETERF (VPG_ES11 + ES11_POINTPARAMETERF) +#define VPC_ES11POINTPARAMETERFV (VPG_ES11 + ES11_POINTPARAMETERFV) +#define VPC_ES11POINTPARAMETERX (VPG_ES11 + ES11_POINTPARAMETERX) +#define VPC_ES11POINTPARAMETERXV (VPG_ES11 + ES11_POINTPARAMETERXV) +#define VPC_ES11POINTSIZE (VPG_ES11 + ES11_POINTSIZE) +#define VPC_ES11POINTSIZEX (VPG_ES11 + ES11_POINTSIZEX) +#define VPC_ES11POLYGONOFFSET (VPG_ES11 + ES11_POLYGONOFFSET) +#define VPC_ES11POLYGONOFFSETX (VPG_ES11 + ES11_POLYGONOFFSETX) +#define VPC_ES11POPMATRIX (VPG_ES11 + ES11_POPMATRIX) +#define VPC_ES11PUSHMATRIX (VPG_ES11 + ES11_PUSHMATRIX) +#define VPC_ES11READPIXELS (VPG_ES11 + ES11_READPIXELS) +#define VPC_ES11ROTATEF (VPG_ES11 + ES11_ROTATEF) +#define VPC_ES11ROTATEX (VPG_ES11 + ES11_ROTATEX) +#define VPC_ES11SAMPLECOVERAGE (VPG_ES11 + ES11_SAMPLECOVERAGE) +#define VPC_ES11SAMPLECOVERAGEX (VPG_ES11 + ES11_SAMPLECOVERAGEX) +#define VPC_ES11SCALEF (VPG_ES11 + ES11_SCALEF) +#define VPC_ES11SCALEX (VPG_ES11 + ES11_SCALEX) +#define VPC_ES11SCISSOR (VPG_ES11 + ES11_SCISSOR) +#define VPC_ES11SHADEMODEL (VPG_ES11 + ES11_SHADEMODEL) +#define VPC_ES11STENCILFUNC (VPG_ES11 + ES11_STENCILFUNC) +#define VPC_ES11STENCILMASK (VPG_ES11 + ES11_STENCILMASK) +#define VPC_ES11STENCILOP (VPG_ES11 + ES11_STENCILOP) +#define VPC_ES11TEXCOORDPOINTER (VPG_ES11 + ES11_TEXCOORDPOINTER) +#define VPC_ES11TEXENVF (VPG_ES11 + ES11_TEXENVF) +#define VPC_ES11TEXENVFV (VPG_ES11 + ES11_TEXENVFV) +#define VPC_ES11TEXENVI (VPG_ES11 + ES11_TEXENVI) +#define VPC_ES11TEXENVIV (VPG_ES11 + ES11_TEXENVIV) +#define VPC_ES11TEXENVX (VPG_ES11 + ES11_TEXENVX) +#define VPC_ES11TEXENVXV (VPG_ES11 + ES11_TEXENVXV) +#define VPC_ES11TEXIMAGE2D (VPG_ES11 + ES11_TEXIMAGE2D) +#define VPC_ES11TEXPARAMETERF (VPG_ES11 + ES11_TEXPARAMETERF) +#define VPC_ES11TEXPARAMETERFV (VPG_ES11 + ES11_TEXPARAMETERFV) +#define VPC_ES11TEXPARAMETERI (VPG_ES11 + ES11_TEXPARAMETERI) +#define VPC_ES11TEXPARAMETERIV (VPG_ES11 + ES11_TEXPARAMETERIV) +#define VPC_ES11TEXPARAMETERX (VPG_ES11 + ES11_TEXPARAMETERX) +#define VPC_ES11TEXPARAMETERXV (VPG_ES11 + ES11_TEXPARAMETERXV) +#define VPC_ES11TEXSUBIMAGE2D (VPG_ES11 + ES11_TEXSUBIMAGE2D) +#define VPC_ES11TRANSLATEF (VPG_ES11 + ES11_TRANSLATEF) +#define VPC_ES11TRANSLATEX (VPG_ES11 + ES11_TRANSLATEX) +#define VPC_ES11VERTEXPOINTER (VPG_ES11 + ES11_VERTEXPOINTER) +#define VPC_ES11VIEWPORT (VPG_ES11 + ES11_VIEWPORT) +/* OpenGL ES11 Statics Counter IDs. */ +#define VPC_ES11CALLS (VPG_ES11 + ES11_CALLS) +#define VPC_ES11DRAWCALLS (VPG_ES11 + ES11_DRAWCALLS) +#define VPC_ES11STATECHANGECALLS (VPG_ES11 + ES11_STATECHANGECALLS) +#define VPC_ES11POINTCOUNT (VPG_ES11 + ES11_POINTCOUNT) +#define VPC_ES11LINECOUNT (VPG_ES11 + ES11_LINECOUNT) +#define VPC_ES11TRIANGLECOUNT (VPG_ES11 + ES11_TRIANGLECOUNT) + +/* OpenGLES 2.x */ +#define VPC_ES20ACTIVETEXTURE (VPG_ES20 + ES20_ACTIVETEXTURE) +#define VPC_ES20ATTACHSHADER (VPG_ES20 + ES20_ATTACHSHADER) +#define VPC_ES20BINDATTRIBLOCATION (VPG_ES20 + ES20_BINDATTRIBLOCATION) +#define VPC_ES20BINDBUFFER (VPG_ES20 + ES20_BINDBUFFER) +#define VPC_ES20BINDFRAMEBUFFER (VPG_ES20 + ES20_BINDFRAMEBUFFER) +#define VPC_ES20BINDRENDERBUFFER (VPG_ES20 + ES20_BINDRENDERBUFFER) +#define VPC_ES20BINDTEXTURE (VPG_ES20 + ES20_BINDTEXTURE) +#define VPC_ES20BLENDCOLOR (VPG_ES20 + ES20_BLENDCOLOR) +#define VPC_ES20BLENDEQUATION (VPG_ES20 + ES20_BLENDEQUATION) +#define VPC_ES20BLENDEQUATIONSEPARATE (VPG_ES20 + ES20_BLENDEQUATIONSEPARATE) +#define VPC_ES20BLENDFUNC (VPG_ES20 + ES20_BLENDFUNC) +#define VPC_ES20BLENDFUNCSEPARATE (VPG_ES20 + ES20_BLENDFUNCSEPARATE) +#define VPC_ES20BUFFERDATA (VPG_ES20 + ES20_BUFFERDATA) +#define VPC_ES20BUFFERSUBDATA (VPG_ES20 + ES20_BUFFERSUBDATA) +#define VPC_ES20CHECKFRAMEBUFFERSTATUS (VPG_ES20 + ES20_CHECKFRAMEBUFFERSTATUS) +#define VPC_ES20CLEAR (VPG_ES20 + ES20_CLEAR) +#define VPC_ES20CLEARCOLOR (VPG_ES20 + ES20_CLEARCOLOR) +#define VPC_ES20CLEARDEPTHF (VPG_ES20 + ES20_CLEARDEPTHF) +#define VPC_ES20CLEARSTENCIL (VPG_ES20 + ES20_CLEARSTENCIL) +#define VPC_ES20COLORMASK (VPG_ES20 + ES20_COLORMASK) +#define VPC_ES20COMPILESHADER (VPG_ES20 + ES20_COMPILESHADER) +#define VPC_ES20COMPRESSEDTEXIMAGE2D (VPG_ES20 + ES20_COMPRESSEDTEXIMAGE2D) +#define VPC_ES20COMPRESSEDTEXSUBIMAGE2D (VPG_ES20 + ES20_COMPRESSEDTEXSUBIMAGE2D) +#define VPC_ES20COPYTEXIMAGE2D (VPG_ES20 + ES20_COPYTEXIMAGE2D) +#define VPC_ES20COPYTEXSUBIMAGE2D (VPG_ES20 + ES20_COPYTEXSUBIMAGE2D) +#define VPC_ES20CREATEPROGRAM (VPG_ES20 + ES20_CREATEPROGRAM) +#define VPC_ES20CREATESHADER (VPG_ES20 + ES20_CREATESHADER) +#define VPC_ES20CULLFACE (VPG_ES20 + ES20_CULLFACE) +#define VPC_ES20DELETEBUFFERS (VPG_ES20 + ES20_DELETEBUFFERS) +#define VPC_ES20DELETEFRAMEBUFFERS (VPG_ES20 + ES20_DELETEFRAMEBUFFERS) +#define VPC_ES20DELETEPROGRAM (VPG_ES20 + ES20_DELETEPROGRAM) +#define VPC_ES20DELETERENDERBUFFERS (VPG_ES20 + ES20_DELETERENDERBUFFERS) +#define VPC_ES20DELETESHADER (VPG_ES20 + ES20_DELETESHADER) +#define VPC_ES20DELETETEXTURES (VPG_ES20 + ES20_DELETETEXTURES) +#define VPC_ES20DEPTHFUNC (VPG_ES20 + ES20_DEPTHFUNC) +#define VPC_ES20DEPTHMASK (VPG_ES20 + ES20_DEPTHMASK) +#define VPC_ES20DEPTHRANGEF (VPG_ES20 + ES20_DEPTHRANGEF) +#define VPC_ES20DETACHSHADER (VPG_ES20 + ES20_DETACHSHADER) +#define VPC_ES20DISABLE (VPG_ES20 + ES20_DISABLE) +#define VPC_ES20DISABLEVERTEXATTRIBARRAY (VPG_ES20 + ES20_DISABLEVERTEXATTRIBARRAY) +#define VPC_ES20DRAWARRAYS (VPG_ES20 + ES20_DRAWARRAYS) +#define VPC_ES20DRAWELEMENTS (VPG_ES20 + ES20_DRAWELEMENTS) +#define VPC_ES20ENABLE (VPG_ES20 + ES20_ENABLE) +#define VPC_ES20ENABLEVERTEXATTRIBARRAY (VPG_ES20 + ES20_ENABLEVERTEXATTRIBARRAY) +#define VPC_ES20FINISH (VPG_ES20 + ES20_FINISH) +#define VPC_ES20FLUSH (VPG_ES20 + ES20_FLUSH) +#define VPC_ES20FRAMEBUFFERRENDERBUFFER (VPG_ES20 + ES20_FRAMEBUFFERRENDERBUFFER) +#define VPC_ES20FRAMEBUFFERTEXTURE2D (VPG_ES20 + ES20_FRAMEBUFFERTEXTURE2D) +#define VPC_ES20FRONTFACE (VPG_ES20 + ES20_FRONTFACE) +#define VPC_ES20GENBUFFERS (VPG_ES20 + ES20_GENBUFFERS) +#define VPC_ES20GENERATEMIPMAP (VPG_ES20 + ES20_GENERATEMIPMAP) +#define VPC_ES20GENFRAMEBUFFERS (VPG_ES20 + ES20_GENFRAMEBUFFERS) +#define VPC_ES20GENRENDERBUFFERS (VPG_ES20 + ES20_GENRENDERBUFFERS) +#define VPC_ES20GENTEXTURES (VPG_ES20 + ES20_GENTEXTURES) +#define VPC_ES20GETACTIVEATTRIB (VPG_ES20 + ES20_GETACTIVEATTRIB) +#define VPC_ES20GETACTIVEUNIFORM (VPG_ES20 + ES20_GETACTIVEUNIFORM) +#define VPC_ES20GETATTACHEDSHADERS (VPG_ES20 + ES20_GETATTACHEDSHADERS) +#define VPC_ES20GETATTRIBLOCATION (VPG_ES20 + ES20_GETATTRIBLOCATION) +#define VPC_ES20GETBOOLEANV (VPG_ES20 + ES20_GETBOOLEANV) +#define VPC_ES20GETBUFFERPARAMETERIV (VPG_ES20 + ES20_GETBUFFERPARAMETERIV) +#define VPC_ES20GETERROR (VPG_ES20 + ES20_GETERROR) +#define VPC_ES20GETFLOATV (VPG_ES20 + ES20_GETFLOATV) +#define VPC_ES20GETFRAMEBUFFERATTACHMENTPARAMETERIV (VPG_ES20 + ES20_GETFRAMEBUFFERATTACHMENTPARAMETERIV) +#define VPC_ES20GETINTEGERV (VPG_ES20 + ES20_GETINTEGERV) +#define VPC_ES20GETPROGRAMIV (VPG_ES20 + ES20_GETPROGRAMIV) +#define VPC_ES20GETPROGRAMINFOLOG (VPG_ES20 + ES20_GETPROGRAMINFOLOG) +#define VPC_ES20GETRENDERBUFFERPARAMETERIV (VPG_ES20 + ES20_GETRENDERBUFFERPARAMETERIV) +#define VPC_ES20GETSHADERIV (VPG_ES20 + ES20_GETSHADERIV) +#define VPC_ES20GETSHADERINFOLOG (VPG_ES20 + ES20_GETSHADERINFOLOG) +#define VPC_ES20GETSHADERPRECISIONFORMAT (VPG_ES20 + ES20_GETSHADERPRECISIONFORMAT) +#define VPC_ES20GETSHADERSOURCE (VPG_ES20 + ES20_GETSHADERSOURCE) +#define VPC_ES20GETSTRING (VPG_ES20 + ES20_GETSTRING) +#define VPC_ES20GETTEXPARAMETERFV (VPG_ES20 + ES20_GETTEXPARAMETERFV) +#define VPC_ES20GETTEXPARAMETERIV (VPG_ES20 + ES20_GETTEXPARAMETERIV) +#define VPC_ES20GETUNIFORMFV (VPG_ES20 + ES20_GETUNIFORMFV) +#define VPC_ES20GETUNIFORMIV (VPG_ES20 + ES20_GETUNIFORMIV) +#define VPC_ES20GETUNIFORMLOCATION (VPG_ES20 + ES20_GETUNIFORMLOCATION) +#define VPC_ES20GETVERTEXATTRIBFV (VPG_ES20 + ES20_GETVERTEXATTRIBFV) +#define VPC_ES20GETVERTEXATTRIBIV (VPG_ES20 + ES20_GETVERTEXATTRIBIV) +#define VPC_ES20GETVERTEXATTRIBPOINTERV (VPG_ES20 + ES20_GETVERTEXATTRIBPOINTERV) +#define VPC_ES20HINT (VPG_ES20 + ES20_HINT) +#define VPC_ES20ISBUFFER (VPG_ES20 + ES20_ISBUFFER) +#define VPC_ES20ISENABLED (VPG_ES20 + ES20_ISENABLED) +#define VPC_ES20ISFRAMEBUFFER (VPG_ES20 + ES20_ISFRAMEBUFFER) +#define VPC_ES20ISPROGRAM (VPG_ES20 + ES20_ISPROGRAM) +#define VPC_ES20ISRENDERBUFFER (VPG_ES20 + ES20_ISRENDERBUFFER) +#define VPC_ES20ISSHADER (VPG_ES20 + ES20_ISSHADER) +#define VPC_ES20ISTEXTURE (VPG_ES20 + ES20_ISTEXTURE) +#define VPC_ES20LINEWIDTH (VPG_ES20 + ES20_LINEWIDTH) +#define VPC_ES20LINKPROGRAM (VPG_ES20 + ES20_LINKPROGRAM) +#define VPC_ES20PIXELSTOREI (VPG_ES20 + ES20_PIXELSTOREI) +#define VPC_ES20POLYGONOFFSET (VPG_ES20 + ES20_POLYGONOFFSET) +#define VPC_ES20READPIXELS (VPG_ES20 + ES20_READPIXELS) +#define VPC_ES20RELEASESHADERCOMPILER (VPG_ES20 + ES20_RELEASESHADERCOMPILER) +#define VPC_ES20RENDERBUFFERSTORAGE (VPG_ES20 + ES20_RENDERBUFFERSTORAGE) +#define VPC_ES20SAMPLECOVERAGE (VPG_ES20 + ES20_SAMPLECOVERAGE) +#define VPC_ES20SCISSOR (VPG_ES20 + ES20_SCISSOR) +#define VPC_ES20SHADERBINARY (VPG_ES20 + ES20_SHADERBINARY) +#define VPC_ES20SHADERSOURCE (VPG_ES20 + ES20_SHADERSOURCE) +#define VPC_ES20STENCILFUNC (VPG_ES20 + ES20_STENCILFUNC) +#define VPC_ES20STENCILFUNCSEPARATE (VPG_ES20 + ES20_STENCILFUNCSEPARATE) +#define VPC_ES20STENCILMASK (VPG_ES20 + ES20_STENCILMASK) +#define VPC_ES20STENCILMASKSEPARATE (VPG_ES20 + ES20_STENCILMASKSEPARATE) +#define VPC_ES20STENCILOP (VPG_ES20 + ES20_STENCILOP) +#define VPC_ES20STENCILOPSEPARATE (VPG_ES20 + ES20_STENCILOPSEPARATE) +#define VPC_ES20TEXIMAGE2D (VPG_ES20 + ES20_TEXIMAGE2D) +#define VPC_ES20TEXPARAMETERF (VPG_ES20 + ES20_TEXPARAMETERF) +#define VPC_ES20TEXPARAMETERFV (VPG_ES20 + ES20_TEXPARAMETERFV) +#define VPC_ES20TEXPARAMETERI (VPG_ES20 + ES20_TEXPARAMETERI) +#define VPC_ES20TEXPARAMETERIV (VPG_ES20 + ES20_TEXPARAMETERIV) +#define VPC_ES20TEXSUBIMAGE2D (VPG_ES20 + ES20_TEXSUBIMAGE2D) +#define VPC_ES20UNIFORM1F (VPG_ES20 + ES20_UNIFORM1F) +#define VPC_ES20UNIFORM1FV (VPG_ES20 + ES20_UNIFORM1FV) +#define VPC_ES20UNIFORM1I (VPG_ES20 + ES20_UNIFORM1I) +#define VPC_ES20UNIFORM1IV (VPG_ES20 + ES20_UNIFORM1IV) +#define VPC_ES20UNIFORM2F (VPG_ES20 + ES20_UNIFORM2F) +#define VPC_ES20UNIFORM2FV (VPG_ES20 + ES20_UNIFORM2FV) +#define VPC_ES20UNIFORM2I (VPG_ES20 + ES20_UNIFORM2I) +#define VPC_ES20UNIFORM2IV (VPG_ES20 + ES20_UNIFORM2IV) +#define VPC_ES20UNIFORM3F (VPG_ES20 + ES20_UNIFORM3F) +#define VPC_ES20UNIFORM3FV (VPG_ES20 + ES20_UNIFORM3FV) +#define VPC_ES20UNIFORM3I (VPG_ES20 + ES20_UNIFORM3I) +#define VPC_ES20UNIFORM3IV (VPG_ES20 + ES20_UNIFORM3IV) +#define VPC_ES20UNIFORM4F (VPG_ES20 + ES20_UNIFORM4F) +#define VPC_ES20UNIFORM4FV (VPG_ES20 + ES20_UNIFORM4FV) +#define VPC_ES20UNIFORM4I (VPG_ES20 + ES20_UNIFORM4I) +#define VPC_ES20UNIFORM4IV (VPG_ES20 + ES20_UNIFORM4IV) +#define VPC_ES20UNIFORMMATRIX2FV (VPG_ES20 + ES20_UNIFORMMATRIX2FV) +#define VPC_ES20UNIFORMMATRIX3FV (VPG_ES20 + ES20_UNIFORMMATRIX3FV) +#define VPC_ES20UNIFORMMATRIX4FV (VPG_ES20 + ES20_UNIFORMMATRIX4FV) +#define VPC_ES20USEPROGRAM (VPG_ES20 + ES20_USEPROGRAM) +#define VPC_ES20VALIDATEPROGRAM (VPG_ES20 + ES20_VALIDATEPROGRAM) +#define VPC_ES20VERTEXATTRIB1F (VPG_ES20 + ES20_VERTEXATTRIB1F) +#define VPC_ES20VERTEXATTRIB1FV (VPG_ES20 + ES20_VERTEXATTRIB1FV) +#define VPC_ES20VERTEXATTRIB2F (VPG_ES20 + ES20_VERTEXATTRIB2F) +#define VPC_ES20VERTEXATTRIB2FV (VPG_ES20 + ES20_VERTEXATTRIB2FV) +#define VPC_ES20VERTEXATTRIB3F (VPG_ES20 + ES20_VERTEXATTRIB3F) +#define VPC_ES20VERTEXATTRIB3FV (VPG_ES20 + ES20_VERTEXATTRIB3FV) +#define VPC_ES20VERTEXATTRIB4F (VPG_ES20 + ES20_VERTEXATTRIB4F) +#define VPC_ES20VERTEXATTRIB4FV (VPG_ES20 + ES20_VERTEXATTRIB4FV) +#define VPC_ES20VERTEXATTRIBPOINTER (VPG_ES20 + ES20_VERTEXATTRIBPOINTER) +#define VPC_ES20VIEWPORT (VPG_ES20 + ES20_VIEWPORT) +/* OpenGL ES20 Statistics Counter IDs. */ +#define VPC_ES20CALLS (VPG_ES20 + ES20_CALLS) +#define VPC_ES20DRAWCALLS (VPG_ES20 + ES20_DRAWCALLS) +#define VPC_ES20STATECHANGECALLS (VPG_ES20 + ES20_STATECHANGECALLS) +#define VPC_ES20POINTCOUNT (VPG_ES20 + ES20_POINTCOUNT) +#define VPC_ES20LINECOUNT (VPG_ES20 + ES20_LINECOUNT) +#define VPC_ES20TRIANGLECOUNT (VPG_ES20 + ES20_TRIANGLECOUNT) + +/* VG11 Counters. */ +#define VPC_VG11APPENDPATH (VPG_VG11 + VG11_APPENDPATH) +#define VPC_VG11APPENDPATHDATA (VPG_VG11 + VG11_APPENDPATHDATA) +#define VPC_VG11CHILDIMAGE (VPG_VG11 + VG11_CHILDIMAGE) +#define VPC_VG11CLEAR (VPG_VG11 + VG11_CLEAR) +#define VPC_VG11CLEARGLYPH (VPG_VG11 + VG11_CLEARGLYPH) +#define VPC_VG11CLEARIMAGE (VPG_VG11 + VG11_CLEARIMAGE) +#define VPC_VG11CLEARPATH (VPG_VG11 + VG11_CLEARPATH) +#define VPC_VG11COLORMATRIX (VPG_VG11 + VG11_COLORMATRIX) +#define VPC_VG11CONVOLVE (VPG_VG11 + VG11_CONVOLVE) +#define VPC_VG11COPYIMAGE (VPG_VG11 + VG11_COPYIMAGE) +#define VPC_VG11COPYMASK (VPG_VG11 + VG11_COPYMASK) +#define VPC_VG11COPYPIXELS (VPG_VG11 + VG11_COPYPIXELS) +#define VPC_VG11CREATEFONT (VPG_VG11 + VG11_CREATEFONT) +#define VPC_VG11CREATEIMAGE (VPG_VG11 + VG11_CREATEIMAGE) +#define VPC_VG11CREATEMASKLAYER (VPG_VG11 + VG11_CREATEMASKLAYER) +#define VPC_VG11CREATEPAINT (VPG_VG11 + VG11_CREATEPAINT) +#define VPC_VG11CREATEPATH (VPG_VG11 + VG11_CREATEPATH) +#define VPC_VG11DESTROYFONT (VPG_VG11 + VG11_DESTROYFONT) +#define VPC_VG11DESTROYIMAGE (VPG_VG11 + VG11_DESTROYIMAGE) +#define VPC_VG11DESTROYMASKLAYER (VPG_VG11 + VG11_DESTROYMASKLAYER) +#define VPC_VG11DESTROYPAINT (VPG_VG11 + VG11_DESTROYPAINT) +#define VPC_VG11DESTROYPATH (VPG_VG11 + VG11_DESTROYPATH) +#define VPC_VG11DRAWGLYPH (VPG_VG11 + VG11_DRAWGLYPH) +#define VPC_VG11DRAWGLYPHS (VPG_VG11 + VG11_DRAWGLYPHS) +#define VPC_VG11DRAWIMAGE (VPG_VG11 + VG11_DRAWIMAGE) +#define VPC_VG11DRAWPATH (VPG_VG11 + VG11_DRAWPATH) +#define VPC_VG11FILLMASKLAYER (VPG_VG11 + VG11_FILLMASKLAYER) +#define VPC_VG11FINISH (VPG_VG11 + VG11_FINISH) +#define VPC_VG11FLUSH (VPG_VG11 + VG11_FLUSH) +#define VPC_VG11GAUSSIANBLUR (VPG_VG11 + VG11_GAUSSIANBLUR) +#define VPC_VG11GETCOLOR (VPG_VG11 + VG11_GETCOLOR) +#define VPC_VG11GETERROR (VPG_VG11 + VG11_GETERROR) +#define VPC_VG11GETF (VPG_VG11 + VG11_GETF) +#define VPC_VG11GETFV (VPG_VG11 + VG11_GETFV) +#define VPC_VG11GETI (VPG_VG11 + VG11_GETI) +#define VPC_VG11GETIMAGESUBDATA (VPG_VG11 + VG11_GETIMAGESUBDATA) +#define VPC_VG11GETIV (VPG_VG11 + VG11_GETIV) +#define VPC_VG11GETMATRIX (VPG_VG11 + VG11_GETMATRIX) +#define VPC_VG11GETPAINT (VPG_VG11 + VG11_GETPAINT) +#define VPC_VG11GETPARAMETERF (VPG_VG11 + VG11_GETPARAMETERF) +#define VPC_VG11GETPARAMETERFV (VPG_VG11 + VG11_GETPARAMETERFV) +#define VPC_VG11GETPARAMETERI (VPG_VG11 + VG11_GETPARAMETERI) +#define VPC_VG11GETPARAMETERIV (VPG_VG11 + VG11_GETPARAMETERIV) +#define VPC_VG11GETPARAMETERVECTORSIZE (VPG_VG11 + VG11_GETPARAMETERVECTORSIZE) +#define VPC_VG11GETPARENT (VPG_VG11 + VG11_GETPARENT) +#define VPC_VG11GETPATHCAPABILITIES (VPG_VG11 + VG11_GETPATHCAPABILITIES) +#define VPC_VG11GETPIXELS (VPG_VG11 + VG11_GETPIXELS) +#define VPC_VG11GETSTRING (VPG_VG11 + VG11_GETSTRING) +#define VPC_VG11GETVECTORSIZE (VPG_VG11 + VG11_GETVECTORSIZE) +#define VPC_VG11HARDWAREQUERY (VPG_VG11 + VG11_HARDWAREQUERY) +#define VPC_VG11IMAGESUBDATA (VPG_VG11 + VG11_IMAGESUBDATA) +#define VPC_VG11INTERPOLATEPATH (VPG_VG11 + VG11_INTERPOLATEPATH) +#define VPC_VG11LOADIDENTITY (VPG_VG11 + VG11_LOADIDENTITY) +#define VPC_VG11LOADMATRIX (VPG_VG11 + VG11_LOADMATRIX) +#define VPC_VG11LOOKUP (VPG_VG11 + VG11_LOOKUP) +#define VPC_VG11LOOKUPSINGLE (VPG_VG11 + VG11_LOOKUPSINGLE) +#define VPC_VG11MASK (VPG_VG11 + VG11_MASK) +#define VPC_VG11MODIFYPATHCOORDS (VPG_VG11 + VG11_MODIFYPATHCOORDS) +#define VPC_VG11MULTMATRIX (VPG_VG11 + VG11_MULTMATRIX) +#define VPC_VG11PAINTPATTERN (VPG_VG11 + VG11_PAINTPATTERN) +#define VPC_VG11PATHBOUNDS (VPG_VG11 + VG11_PATHBOUNDS) +#define VPC_VG11PATHLENGTH (VPG_VG11 + VG11_PATHLENGTH) +#define VPC_VG11PATHTRANSFORMEDBOUNDS (VPG_VG11 + VG11_PATHTRANSFORMEDBOUNDS) +#define VPC_VG11POINTALONGPATH (VPG_VG11 + VG11_POINTALONGPATH) +#define VPC_VG11READPIXELS (VPG_VG11 + VG11_READPIXELS) +#define VPC_VG11REMOVEPATHCAPABILITIES (VPG_VG11 + VG11_REMOVEPATHCAPABILITIES) +#define VPC_VG11RENDERTOMASK (VPG_VG11 + VG11_RENDERTOMASK) +#define VPC_VG11ROTATE (VPG_VG11 + VG11_ROTATE) +#define VPC_VG11SCALE (VPG_VG11 + VG11_SCALE) +#define VPC_VG11SEPARABLECONVOLVE (VPG_VG11 + VG11_SEPARABLECONVOLVE) +#define VPC_VG11SETCOLOR (VPG_VG11 + VG11_SETCOLOR) +#define VPC_VG11SETF (VPG_VG11 + VG11_SETF) +#define VPC_VG11SETFV (VPG_VG11 + VG11_SETFV) +#define VPC_VG11SETGLYPHTOIMAGE (VPG_VG11 + VG11_SETGLYPHTOIMAGE) +#define VPC_VG11SETGLYPHTOPATH (VPG_VG11 + VG11_SETGLYPHTOPATH) +#define VPC_VG11SETI (VPG_VG11 + VG11_SETI) +#define VPC_VG11SETIV (VPG_VG11 + VG11_SETIV) +#define VPC_VG11SETPAINT (VPG_VG11 + VG11_SETPAINT) +#define VPC_VG11SETPARAMETERF (VPG_VG11 + VG11_SETPARAMETERF) +#define VPC_VG11SETPARAMETERFV (VPG_VG11 + VG11_SETPARAMETERFV) +#define VPC_VG11SETPARAMETERI (VPG_VG11 + VG11_SETPARAMETERI) +#define VPC_VG11SETPARAMETERIV (VPG_VG11 + VG11_SETPARAMETERIV) +#define VPC_VG11SETPIXELS (VPG_VG11 + VG11_SETPIXELS) +#define VPC_VG11SHEAR (VPG_VG11 + VG11_SHEAR) +#define VPC_VG11TRANSFORMPATH (VPG_VG11 + VG11_TRANSFORMPATH) +#define VPC_VG11TRANSLATE (VPG_VG11 + VG11_TRANSLATE) +#define VPC_VG11WRITEPIXELS (VPG_VG11 + VG11_WRITEPIXELS) +/* OpenVG Statistics Counter IDs. */ +#define VPC_VG11CALLS (VPG_VG11 + VG11_CALLS) +#define VPC_VG11DRAWCALLS (VPG_VG11 + VG11_DRAWCALLS) +#define VPC_VG11STATECHANGECALLS (VPG_VG11 + VG11_STATECHANGECALLS) +#define VPC_VG11FILLCOUNT (VPG_VG11 + VG11_FILLCOUNT) +#define VPC_VG11STROKECOUNT (VPG_VG11 + VG11_STROKECOUNT) + +/* HAL Counters. */ +#define VPC_HALVERTBUFNEWBYTEALLOC (VPG_HAL + HAL_VERTBUFNEWBYTEALLOC) +#define VPC_HALVERTBUFTOTALBYTEALLOC (VPG_HAL + HAL_VERTBUFTOTALBYTEALLOC) +#define VPC_HALVERTBUFNEWOBJALLOC (VPG_HAL + HAL_VERTBUFNEWOBJALLOC) +#define VPC_HALVERTBUFTOTALOBJALLOC (VPG_HAL + HAL_VERTBUFTOTALOBJALLOC) +#define VPC_HALINDBUFNEWBYTEALLOC (VPG_HAL + HAL_INDBUFNEWBYTEALLOC) +#define VPC_HALINDBUFTOTALBYTEALLOC (VPG_HAL + HAL_INDBUFTOTALBYTEALLOC) +#define VPC_HALINDBUFNEWOBJALLOC (VPG_HAL + HAL_INDBUFNEWOBJALLOC) +#define VPC_HALINDBUFTOTALOBJALLOC (VPG_HAL + HAL_INDBUFTOTALOBJALLOC) +#define VPC_HALTEXBUFNEWBYTEALLOC (VPG_HAL + HAL_TEXBUFNEWBYTEALLOC) +#define VPC_HALTEXBUFTOTALBYTEALLOC (VPG_HAL + HAL_TEXBUFTOTALBYTEALLOC) +#define VPC_HALTEXBUFNEWOBJALLOC (VPG_HAL + HAL_TEXBUFNEWOBJALLOC) +#define VPC_HALTEXBUFTOTALOBJALLOC (VPG_HAL + HAL_TEXBUFTOTALOBJALLOC) + +/* HW: GPU Counters. */ +#define VPC_GPUCYCLES (VPG_GPU + GPU_CYCLES) +#define VPC_GPUREAD64BYTE (VPG_GPU + GPU_READ64BYTE) +#define VPC_GPUWRITE64BYTE (VPG_GPU + GPU_WRITE64BYTE) + +/* HW: Shader Counters. */ +#define VPC_VSINSTCOUNT (VPG_VS + VS_INSTCOUNT) +#define VPC_VSBRANCHINSTCOUNT (VPG_VS + VS_BRANCHINSTCOUNT) +#define VPC_VSTEXLDINSTCOUNT (VPG_VS + VS_TEXLDINSTCOUNT) +#define VPC_VSRENDEREDVERTCOUNT (VPG_VS + VS_RENDEREDVERTCOUNT) +/* HW: PS Count. */ +#define VPC_PSINSTCOUNT (VPG_PS + PS_INSTCOUNT) +#define VPC_PSBRANCHINSTCOUNT (VPG_PS + PS_BRANCHINSTCOUNT) +#define VPC_PSTEXLDINSTCOUNT (VPG_PS + PS_TEXLDINSTCOUNT) +#define VPC_PSRENDEREDPIXCOUNT (VPG_PS + PS_RENDEREDPIXCOUNT) + + +/* HW: PA Counters. */ +#define VPC_PAINVERTCOUNT (VPG_PA + PA_INVERTCOUNT) +#define VPC_PAINPRIMCOUNT (VPG_PA + PA_INPRIMCOUNT) +#define VPC_PAOUTPRIMCOUNT (VPG_PA + PA_OUTPRIMCOUNT) +#define VPC_PADEPTHCLIPCOUNT (VPG_PA + PA_DEPTHCLIPCOUNT) +#define VPC_PATRIVIALREJCOUNT (VPG_PA + PA_TRIVIALREJCOUNT) +#define VPC_PACULLCOUNT (VPG_PA + PA_CULLCOUNT) + +/* HW: Setup Counters. */ +#define VPC_SETRIANGLECOUNT (VPG_SETUP + SE_TRIANGLECOUNT) +#define VPC_SELINECOUNT (VPG_SETUP + SE_LINECOUNT) + +/* HW: RA Counters. */ +#define VPC_RAVALIDPIXCOUNT (VPG_RA + RA_VALIDPIXCOUNT) +#define VPC_RATOTALQUADCOUNT (VPG_RA + RA_TOTALQUADCOUNT) +#define VPC_RAVALIDQUADCOUNTEZ (VPG_RA + RA_VALIDQUADCOUNTEZ) +#define VPC_RATOTALPRIMCOUNT (VPG_RA + RA_TOTALPRIMCOUNT) +#define VPC_RAPIPECACHEMISSCOUNT (VPG_RA + RA_PIPECACHEMISSCOUNT) +#define VPC_RAPREFCACHEMISSCOUNT (VPG_RA + RA_PREFCACHEMISSCOUNT) +#define VPC_RAEEZCULLCOUNT (VPG_RA + RA_EEZCULLCOUNT) + +/* HW: TEX Counters. */ +#define VPC_TXTOTBILINEARREQ (VPG_TX + TX_TOTBILINEARREQ) +#define VPC_TXTOTTRILINEARREQ (VPG_TX + TX_TOTTRILINEARREQ) +#define VPC_TXTOTDISCARDTEXREQ (VPG_TX + TX_TOTDISCARDTEXREQ) +#define VPC_TXTOTTEXREQ (VPG_TX + TX_TOTTEXREQ) +#define VPC_TXMEMREADCOUNT (VPG_TX + TX_MEMREADCOUNT) +#define VPC_TXMEMREADIN8BCOUNT (VPG_TX + TX_MEMREADIN8BCOUNT) +#define VPC_TXCACHEMISSCOUNT (VPG_TX + TX_CACHEMISSCOUNT) +#define VPC_TXCACHEHITTEXELCOUNT (VPG_TX + TX_CACHEHITTEXELCOUNT) +#define VPC_TXCACHEMISSTEXELCOUNT (VPG_TX + TX_CACHEMISSTEXELCOUNT) + +/* HW: PE Counters. */ +#define VPC_PEKILLEDBYCOLOR (VPG_PE + PE_KILLEDBYCOLOR) +#define VPC_PEKILLEDBYDEPTH (VPG_PE + PE_KILLEDBYDEPTH) +#define VPC_PEDRAWNBYCOLOR (VPG_PE + PE_DRAWNBYCOLOR) +#define VPC_PEDRAWNBYDEPTH (VPG_PE + PE_DRAWNBYDEPTH) + +/* HW: MC Counters. */ +#define VPC_MCREADREQ8BPIPE (VPG_MC + MC_READREQ8BPIPE) +#define VPC_MCREADREQ8BIP (VPG_MC + MC_READREQ8BIP) +#define VPC_MCWRITEREQ8BPIPE (VPG_MC + MC_WRITEREQ8BPIPE) + +/* HW: AXI Counters. */ +#define VPC_AXIREADREQSTALLED (VPG_AXI + AXI_READREQSTALLED) +#define VPC_AXIWRITEREQSTALLED (VPG_AXI + AXI_WRITEREQSTALLED) +#define VPC_AXIWRITEDATASTALLED (VPG_AXI + AXI_WRITEDATASTALLED) + +/* PROGRAM: Shader program counters. */ +#define VPC_PVSINSTRCOUNT (VPG_PVS + PVS_INSTRCOUNT) +#define VPC_PVSALUINSTRCOUNT (VPG_PVS + PVS_ALUINSTRCOUNT) +#define VPC_PVSTEXINSTRCOUNT (VPG_PVS + PVS_TEXINSTRCOUNT) +#define VPC_PVSATTRIBCOUNT (VPG_PVS + PVS_ATTRIBCOUNT) +#define VPC_PVSUNIFORMCOUNT (VPG_PVS + PVS_UNIFORMCOUNT) +#define VPC_PVSFUNCTIONCOUNT (VPG_PVS + PVS_FUNCTIONCOUNT) + +#define VPC_PPSINSTRCOUNT (VPG_PPS + PPS_INSTRCOUNT) +#define VPC_PPSALUINSTRCOUNT (VPG_PPS + PPS_ALUINSTRCOUNT) +#define VPC_PPSTEXINSTRCOUNT (VPG_PPS + PPS_TEXINSTRCOUNT) +#define VPC_PPSATTRIBCOUNT (VPG_PPS + PPS_ATTRIBCOUNT) +#define VPC_PPSUNIFORMCOUNT (VPG_PPS + PPS_UNIFORMCOUNT) +#define VPC_PPSFUNCTIONCOUNT (VPG_PPS + PPS_FUNCTIONCOUNT) + +#endif + + +/* HW profile information. */ +typedef struct _gcsPROFILER_COUNTERS +{ + /* HW static counters. */ + gctUINT32 gpuClock; + gctUINT32 axiClock; + gctUINT32 shaderClock; + + /* HW vairable counters. */ + gctUINT32 gpuClockStart; + gctUINT32 gpuClockEnd; + + /* HW vairable counters. */ + gctUINT32 gpuCyclesCounter; + gctUINT32 gpuTotalRead64BytesPerFrame; + gctUINT32 gpuTotalWrite64BytesPerFrame; + + /* PE */ + gctUINT32 pe_pixel_count_killed_by_color_pipe; + gctUINT32 pe_pixel_count_killed_by_depth_pipe; + gctUINT32 pe_pixel_count_drawn_by_color_pipe; + gctUINT32 pe_pixel_count_drawn_by_depth_pipe; + + /* SH */ + gctUINT32 ps_inst_counter; + gctUINT32 rendered_pixel_counter; + gctUINT32 vs_inst_counter; + gctUINT32 rendered_vertice_counter; + gctUINT32 vtx_branch_inst_counter; + gctUINT32 vtx_texld_inst_counter; + gctUINT32 pxl_branch_inst_counter; + gctUINT32 pxl_texld_inst_counter; + + /* PA */ + gctUINT32 pa_input_vtx_counter; + gctUINT32 pa_input_prim_counter; + gctUINT32 pa_output_prim_counter; + gctUINT32 pa_depth_clipped_counter; + gctUINT32 pa_trivial_rejected_counter; + gctUINT32 pa_culled_counter; + + /* SE */ + gctUINT32 se_culled_triangle_count; + gctUINT32 se_culled_lines_count; + + /* RA */ + gctUINT32 ra_valid_pixel_count; + gctUINT32 ra_total_quad_count; + gctUINT32 ra_valid_quad_count_after_early_z; + gctUINT32 ra_total_primitive_count; + gctUINT32 ra_pipe_cache_miss_counter; + gctUINT32 ra_prefetch_cache_miss_counter; + gctUINT32 ra_eez_culled_counter; + + /* TX */ + gctUINT32 tx_total_bilinear_requests; + gctUINT32 tx_total_trilinear_requests; + gctUINT32 tx_total_discarded_texture_requests; + gctUINT32 tx_total_texture_requests; + gctUINT32 tx_mem_read_count; + gctUINT32 tx_mem_read_in_8B_count; + gctUINT32 tx_cache_miss_count; + gctUINT32 tx_cache_hit_texel_count; + gctUINT32 tx_cache_miss_texel_count; + + /* MC */ + gctUINT32 mc_total_read_req_8B_from_pipeline; + gctUINT32 mc_total_read_req_8B_from_IP; + gctUINT32 mc_total_write_req_8B_from_pipeline; + + /* HI */ + gctUINT32 hi_axi_cycles_read_request_stalled; + gctUINT32 hi_axi_cycles_write_request_stalled; + gctUINT32 hi_axi_cycles_write_data_stalled; +} +gcsPROFILER_COUNTERS; + +/* HAL profile information. */ +typedef struct _gcsPROFILER +{ + gctUINT32 enable; + gctBOOL enableHal; + gctBOOL enableHW; + gctBOOL enableSH; + + gctBOOL useSocket; + gctINT sockFd; + + gctFILE file; + + /* Aggregate Information */ + + /* Clock Info */ + gctUINT64 frameStart; + gctUINT64 frameEnd; + + /* Current frame information */ + gctUINT32 frameNumber; + gctUINT64 frameStartTimeusec; + gctUINT64 frameEndTimeusec; + gctUINT64 frameStartCPUTimeusec; + gctUINT64 frameEndCPUTimeusec; + +#if PROFILE_HAL_COUNTERS + gctUINT32 vertexBufferTotalBytesAlloc; + gctUINT32 vertexBufferNewBytesAlloc; + int vertexBufferTotalObjectsAlloc; + int vertexBufferNewObjectsAlloc; + + gctUINT32 indexBufferTotalBytesAlloc; + gctUINT32 indexBufferNewBytesAlloc; + int indexBufferTotalObjectsAlloc; + int indexBufferNewObjectsAlloc; + + gctUINT32 textureBufferTotalBytesAlloc; + gctUINT32 textureBufferNewBytesAlloc; + int textureBufferTotalObjectsAlloc; + int textureBufferNewObjectsAlloc; + + gctUINT32 numCommits; + gctUINT32 drawPointCount; + gctUINT32 drawLineCount; + gctUINT32 drawTriangleCount; + gctUINT32 drawVertexCount; + gctUINT32 redundantStateChangeCalls; +#endif + + gctUINT32 prevVSInstCount; + gctUINT32 prevVSBranchInstCount; + gctUINT32 prevVSTexInstCount; + gctUINT32 prevVSVertexCount; + gctUINT32 prevPSInstCount; + gctUINT32 prevPSBranchInstCount; + gctUINT32 prevPSTexInstCount; + gctUINT32 prevPSPixelCount; + +} +gcsPROFILER; + +/* Memory profile information. */ +struct _gcsMemProfile +{ + /* Memory Usage */ + gctUINT32 videoMemUsed; + gctUINT32 systemMemUsed; + gctUINT32 commitBufferSize; + gctUINT32 contextBufferCopyBytes; +}; + +/* Shader profile information. */ +struct _gcsSHADER_PROFILER +{ + gctUINT32 shaderLength; + gctUINT32 shaderALUCycles; + gctUINT32 shaderTexLoadCycles; + gctUINT32 shaderTempRegCount; + gctUINT32 shaderSamplerRegCount; + gctUINT32 shaderInputRegCount; + gctUINT32 shaderOutputRegCount; +}; + +/* Initialize the gcsProfiler. */ +gceSTATUS +gcoPROFILER_Initialize( + IN gcoHAL Hal + ); + +/* Destroy the gcProfiler. */ +gceSTATUS +gcoPROFILER_Destroy( + IN gcoHAL Hal + ); + +/* Write data to profiler. */ +gceSTATUS +gcoPROFILER_Write( + IN gcoHAL Hal, + IN gctSIZE_T ByteCount, + IN gctCONST_POINTER Data + ); + +/* Flush data out. */ +gceSTATUS +gcoPROFILER_Flush( + IN gcoHAL Hal + ); + +/* Call to signal end of frame. */ +gceSTATUS +gcoPROFILER_EndFrame( + IN gcoHAL Hal + ); + +/* Increase profile counter Enum by Value. */ +gceSTATUS +gcoPROFILER_Count( + IN gcoHAL Hal, + IN gctUINT32 Enum, + IN gctINT Value + ); + +/* Profile input vertex shader. */ +gceSTATUS +gcoPROFILER_ShaderVS( + IN gcoHAL Hal, + IN gctPOINTER Vs + ); + +/* Profile input fragment shader. */ +gceSTATUS +gcoPROFILER_ShaderFS( + IN gcoHAL Hal, + IN gctPOINTER Fs + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_profiler_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_raster.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_raster.h new file mode 100644 index 0000000..c303462 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_raster.h @@ -0,0 +1,933 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_raster_h_ +#define __gc_hal_raster_h_ + +#include "gc_hal_enum.h" +#include "gc_hal_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** Object Declarations ***************************** +\******************************************************************************/ + +typedef struct _gcoBRUSH * gcoBRUSH; +typedef struct _gcoBRUSH_CACHE * gcoBRUSH_CACHE; + +/******************************************************************************\ +******************************** gcoBRUSH Object ******************************* +\******************************************************************************/ + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructSingleColor( + IN gcoHAL Hal, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructMonochrome( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_ConstructColor( + IN gcoHAL Hal, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Destroy an gcoBRUSH object. */ +gceSTATUS +gcoBRUSH_Destroy( + IN gcoBRUSH Brush + ); + +/******************************************************************************\ +******************************** gcoSURF Object ******************************* +\******************************************************************************/ + +/* Set cipping rectangle. */ +gceSTATUS +gcoSURF_SetClipping( + IN gcoSURF Surface + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gcoSURF_Clear2D( + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN gcsRECT_PTR DestRect, + IN gctUINT32 LoColor, + IN gctUINT32 HiColor + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gcoSURF_Line( + IN gcoSURF Surface, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop + ); + +/* Generic rectangular blit. */ +gceSTATUS +gcoSURF_Blit( + IN OPTIONAL gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gctUINT32 RectCount, + IN OPTIONAL gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN OPTIONAL gceSURF_TRANSPARENCY Transparency, + IN OPTIONAL gctUINT32 TransparencyColor, + IN OPTIONAL gctPOINTER Mask, + IN OPTIONAL gceSURF_MONOPACK MaskPack + ); + +/* Monochrome blit. */ +gceSTATUS +gcoSURF_MonoBlit( + IN gcoSURF DestSurface, + IN gctPOINTER Source, + IN gceSURF_MONOPACK SourcePack, + IN gcsPOINT_PTR SourceSize, + IN gcsPOINT_PTR SourceOrigin, + IN gcsRECT_PTR DestRect, + IN OPTIONAL gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Filter blit. */ +gceSTATUS +gcoSURF_FilterBlit( + IN gcoSURF SrcSurface, + IN gcoSURF DestSurface, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gcoSURF_EnableAlphaBlend( + IN gcoSURF Surface, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gcoSURF_DisableAlphaBlend( + IN gcoSURF Surface + ); + +/* Copy a rectangular area with format conversion. */ +gceSTATUS +gcoSURF_CopyPixels( + IN gcoSURF Source, + IN gcoSURF Target, + IN gctINT SourceX, + IN gctINT SourceY, + IN gctINT TargetX, + IN gctINT TargetY, + IN gctINT Width, + IN gctINT Height + ); + +/* Read surface pixel. */ +gceSTATUS +gcoSURF_ReadPixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + OUT gctPOINTER PixelValue + ); + +/* Write surface pixel. */ +gceSTATUS +gcoSURF_WritePixel( + IN gcoSURF Surface, + IN gctPOINTER Memory, + IN gctINT X, + IN gctINT Y, + IN gceSURF_FORMAT Format, + IN gctPOINTER PixelValue + ); + +gceSTATUS +gcoSURF_SetDither( + IN gcoSURF Surface, + IN gctBOOL Dither + ); +/******************************************************************************\ +********************************** gco2D Object ********************************* +\******************************************************************************/ + +/* Construct a new gco2D object. */ +gceSTATUS +gco2D_Construct( + IN gcoHAL Hal, + OUT gco2D * Hardware + ); + +/* Destroy an gco2D object. */ +gceSTATUS +gco2D_Destroy( + IN gco2D Hardware + ); + +/* Sets the maximum number of brushes in the brush cache. */ +gceSTATUS +gco2D_SetBrushLimit( + IN gco2D Hardware, + IN gctUINT MaxCount + ); + +/* Flush the brush. */ +gceSTATUS +gco2D_FlushBrush( + IN gco2D Engine, + IN gcoBRUSH Brush, + IN gceSURF_FORMAT Format + ); + +/* Program the specified solid color brush. */ +gceSTATUS +gco2D_LoadSolidBrush( + IN gco2D Engine, + IN gceSURF_FORMAT Format, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask + ); + +gceSTATUS +gco2D_LoadMonochromeBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask + ); + +gceSTATUS +gco2D_LoadColorBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask + ); + +/* Configure monochrome source. */ +gceSTATUS +gco2D_SetMonochromeSource( + IN gco2D Engine, + IN gctBOOL ColorConvert, + IN gctUINT8 MonoTransparency, + IN gceSURF_MONOPACK DataPack, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source extension for full rotation. */ +gceSTATUS +gco2D_SetColorSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative, + IN gceSURF_TRANSPARENCY Transparency, + IN gctUINT32 TransparencyColor + ); + +/* Configure color source. */ +gceSTATUS +gco2D_SetColorSourceAdvanced( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctBOOL CoordRelative + ); + +gceSTATUS +gco2D_SetColorSourceN( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight, + IN gctUINT32 SurfaceNumber + ); + +/* Configure masked color source. */ +gceSTATUS +gco2D_SetMaskedSource( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack + ); + +/* Configure masked color source extension for full rotation. */ +gceSTATUS +gco2D_SetMaskedSourceEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_FORMAT Format, + IN gctBOOL CoordRelative, + IN gceSURF_MONOPACK MaskPack, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Setup the source rectangle. */ +gceSTATUS +gco2D_SetSource( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect + ); + +/* Set clipping rectangle. */ +gceSTATUS +gco2D_SetClipping( + IN gco2D Engine, + IN gcsRECT_PTR Rect + ); + +/* Configure destination. */ +gceSTATUS +gco2D_SetTarget( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth + ); + +/* Configure destination extension for full rotation. */ +gceSTATUS +gco2D_SetTargetEx( + IN gco2D Engine, + IN gctUINT32 Address, + IN gctUINT32 Stride, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight + ); + +/* Calculate and program the stretch factors. */ +gceSTATUS +gco2D_SetStretchFactors( + IN gco2D Engine, + IN gctUINT32 HorFactor, + IN gctUINT32 VerFactor + ); + +/* Calculate and program the stretch factors based on the rectangles. */ +gceSTATUS +gco2D_SetStretchRectFactors( + IN gco2D Engine, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect + ); + +/* Create a new solid color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructSingleColorBrush( + IN gco2D Engine, + IN gctUINT32 ColorConvert, + IN gctUINT32 Color, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a new monochrome gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructMonochromeBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctUINT32 ColorConvert, + IN gctUINT32 FgColor, + IN gctUINT32 BgColor, + IN gctUINT64 Bits, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Create a color gcoBRUSH object. */ +gceSTATUS +gco2D_ConstructColorBrush( + IN gco2D Engine, + IN gctUINT32 OriginX, + IN gctUINT32 OriginY, + IN gctPOINTER Address, + IN gceSURF_FORMAT Format, + IN gctUINT64 Mask, + gcoBRUSH * Brush + ); + +/* Clear one or more rectangular areas. */ +gceSTATUS +gco2D_Clear( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines. */ +gceSTATUS +gco2D_Line( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gcoBRUSH Brush, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Draw one or more Bresenham lines based on the 32-bit color. */ +gceSTATUS +gco2D_ColorLine( + IN gco2D Engine, + IN gctUINT32 LineCount, + IN gcsRECT_PTR Position, + IN gctUINT32 Color32, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Generic blit. */ +gceSTATUS +gco2D_Blit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +gceSTATUS +gco2D_Blend( + IN gco2D Engine, + IN gctUINT32 SrcCount, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Batch blit. */ +gceSTATUS +gco2D_BatchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR SrcRect, + IN gcsRECT_PTR DestRect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Stretch blit. */ +gceSTATUS +gco2D_StretchBlit( + IN gco2D Engine, + IN gctUINT32 RectCount, + IN gcsRECT_PTR Rect, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Monochrome blit. */ +gceSTATUS +gco2D_MonoBlit( + IN gco2D Engine, + IN gctPOINTER StreamBits, + IN gcsPOINT_PTR StreamSize, + IN gcsRECT_PTR StreamRect, + IN gceSURF_MONOPACK SrcStreamPack, + IN gceSURF_MONOPACK DestStreamPack, + IN gcsRECT_PTR DestRect, + IN gctUINT32 FgRop, + IN gctUINT32 BgRop, + IN gceSURF_FORMAT DestFormat + ); + +/* Set kernel size. */ +gceSTATUS +gco2D_SetKernelSize( + IN gco2D Engine, + IN gctUINT8 HorKernelSize, + IN gctUINT8 VerKernelSize + ); + +/* Set filter type. */ +gceSTATUS +gco2D_SetFilterType( + IN gco2D Engine, + IN gceFILTER_TYPE FilterType + ); + +/* Set the filter kernel by user. */ +gceSTATUS +gco2D_SetUserFilterKernel( + IN gco2D Engine, + IN gceFILTER_PASS_TYPE PassType, + IN gctUINT16_PTR KernelArray + ); + +/* Select the pass(es) to be done for user defined filter. */ +gceSTATUS +gco2D_EnableUserFilterPasses( + IN gco2D Engine, + IN gctBOOL HorPass, + IN gctBOOL VerPass + ); + +/* Frees the temporary buffer allocated by filter blit operation. */ +gceSTATUS +gco2D_FreeFilterBuffer( + IN gco2D Engine + ); + +/* Filter blit. */ +gceSTATUS +gco2D_FilterBlit( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Filter blit extension for full rotation. */ +gceSTATUS +gco2D_FilterBlitEx( + IN gco2D Engine, + IN gctUINT32 SrcAddress, + IN gctUINT SrcStride, + IN gctUINT32 SrcUAddress, + IN gctUINT SrcUStride, + IN gctUINT32 SrcVAddress, + IN gctUINT SrcVStride, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gctUINT32 SrcSurfaceHeight, + IN gcsRECT_PTR SrcRect, + IN gctUINT32 DestAddress, + IN gctUINT DestStride, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gctUINT32 DestSurfaceHeight, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +gceSTATUS +gco2D_FilterBlitEx2( + IN gco2D Engine, + IN gctUINT32_PTR SrcAddresses, + IN gctUINT32 SrcAddressNum, + IN gctUINT32_PTR SrcStrides, + IN gctUINT32 SrcStrideNum, + IN gceTILING SrcTiling, + IN gceSURF_FORMAT SrcFormat, + IN gceSURF_ROTATION SrcRotation, + IN gctUINT32 SrcSurfaceWidth, + IN gctUINT32 SrcSurfaceHeight, + IN gcsRECT_PTR SrcRect, + IN gctUINT32_PTR DestAddresses, + IN gctUINT32 DestAddressNum, + IN gctUINT32_PTR DestStrides, + IN gctUINT32 DestStrideNum, + IN gceTILING DestTiling, + IN gceSURF_FORMAT DestFormat, + IN gceSURF_ROTATION DestRotation, + IN gctUINT32 DestSurfaceWidth, + IN gctUINT32 DestSurfaceHeight, + IN gcsRECT_PTR DestRect, + IN gcsRECT_PTR DestSubRect + ); + +/* Enable alpha blending engine in the hardware and disengage the ROP engine. */ +gceSTATUS +gco2D_EnableAlphaBlend( + IN gco2D Engine, + IN gctUINT8 SrcGlobalAlphaValue, + IN gctUINT8 DstGlobalAlphaValue, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode, + IN gceSURF_PIXEL_COLOR_MODE SrcColorMode, + IN gceSURF_PIXEL_COLOR_MODE DstColorMode + ); + +/* Enable alpha blending engine in the hardware. */ +gceSTATUS +gco2D_EnableAlphaBlendAdvanced( + IN gco2D Engine, + IN gceSURF_PIXEL_ALPHA_MODE SrcAlphaMode, + IN gceSURF_PIXEL_ALPHA_MODE DstAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE SrcGlobalAlphaMode, + IN gceSURF_GLOBAL_ALPHA_MODE DstGlobalAlphaMode, + IN gceSURF_BLEND_FACTOR_MODE SrcFactorMode, + IN gceSURF_BLEND_FACTOR_MODE DstFactorMode + ); + +/* Enable alpha blending engine with Porter Duff rule. */ +gceSTATUS +gco2D_SetPorterDuffBlending( + IN gco2D Engine, + IN gce2D_PORTER_DUFF_RULE Rule + ); + +/* Disable alpha blending engine in the hardware and engage the ROP engine. */ +gceSTATUS +gco2D_DisableAlphaBlend( + IN gco2D Engine + ); + +/* Retrieve the maximum number of 32-bit data chunks for a single DE command. */ +gctUINT32 +gco2D_GetMaximumDataCount( + void + ); + +/* Retrieve the maximum number of rectangles, that can be passed in a single DE command. */ +gctUINT32 +gco2D_GetMaximumRectCount( + void + ); + +/* Returns the pixel alignment of the surface. */ +gceSTATUS +gco2D_GetPixelAlignment( + gceSURF_FORMAT Format, + gcsPOINT_PTR Alignment + ); + +/* Retrieve monochrome stream pack size. */ +gceSTATUS +gco2D_GetPackSize( + IN gceSURF_MONOPACK StreamPack, + OUT gctUINT32 * PackWidth, + OUT gctUINT32 * PackHeight + ); + +/* Flush the 2D pipeline. */ +gceSTATUS +gco2D_Flush( + IN gco2D Engine + ); + +/* Load 256-entry color table for INDEX8 source surfaces. */ +gceSTATUS +gco2D_LoadPalette( + IN gco2D Engine, + IN gctUINT FirstIndex, + IN gctUINT IndexCount, + IN gctPOINTER ColorTable, + IN gctBOOL ColorConvert + ); + +/* Enable/disable 2D BitBlt mirrorring. */ +gceSTATUS +gco2D_SetBitBlitMirror( + IN gco2D Engine, + IN gctBOOL HorizontalMirror, + IN gctBOOL VerticalMirror + ); + +/* + * Set the transparency for source, destination and pattern. + * It also enable or disable the DFB color key mode. + */ +gceSTATUS +gco2D_SetTransparencyAdvancedEx( + IN gco2D Engine, + IN gce2D_TRANSPARENCY SrcTransparency, + IN gce2D_TRANSPARENCY DstTransparency, + IN gce2D_TRANSPARENCY PatTransparency, + IN gctBOOL EnableDFBColorKeyMode + ); + +/* Set the transparency for source, destination and pattern. */ +gceSTATUS +gco2D_SetTransparencyAdvanced( + IN gco2D Engine, + IN gce2D_TRANSPARENCY SrcTransparency, + IN gce2D_TRANSPARENCY DstTransparency, + IN gce2D_TRANSPARENCY PatTransparency + ); + +/* Set the source color key. */ +gceSTATUS +gco2D_SetSourceColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the source color key range. */ +gceSTATUS +gco2D_SetSourceColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the target color key. */ +gceSTATUS +gco2D_SetTargetColorKeyAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKey + ); + +/* Set the target color key range. */ +gceSTATUS +gco2D_SetTargetColorKeyRangeAdvanced( + IN gco2D Engine, + IN gctUINT32 ColorKeyLow, + IN gctUINT32 ColorKeyHigh + ); + +/* Set the YUV color space mode. */ +gceSTATUS +gco2D_SetYUVColorMode( + IN gco2D Engine, + IN gce2D_YUV_COLOR_MODE Mode + ); + +/* Setup the source global color value in ARGB8 format. */ +gceSTATUS gco2D_SetSourceGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the target global color value in ARGB8 format. */ +gceSTATUS gco2D_SetTargetGlobalColorAdvanced( + IN gco2D Engine, + IN gctUINT32 Color32 + ); + +/* Setup the source and target pixel multiply modes. */ +gceSTATUS +gco2D_SetPixelMultiplyModeAdvanced( + IN gco2D Engine, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE SrcPremultiplySrcAlpha, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstPremultiplyDstAlpha, + IN gce2D_GLOBAL_COLOR_MULTIPLY_MODE SrcPremultiplyGlobalMode, + IN gce2D_PIXEL_COLOR_MULTIPLY_MODE DstDemultiplyDstAlpha + ); + +/* Set the GPU clock cycles after which the idle engine will keep auto-flushing. */ +gceSTATUS +gco2D_SetAutoFlushCycles( + IN gco2D Engine, + IN gctUINT32 Cycles + ); + +#if VIVANTE_PROFILER +/* Read the profile registers available in the 2D engine and sets them in the profile. + The function will also reset the pixelsRendered counter every time. +*/ +gceSTATUS +gco2D_ProfileEngine( + IN gco2D Engine, + OPTIONAL gcs2D_PROFILE_PTR Profile + ); +#endif + +/* Enable or disable 2D dithering. */ +gceSTATUS +gco2D_EnableDither( + IN gco2D Engine, + IN gctBOOL Enable + ); + +gceSTATUS +gco2D_SetGenericSource( + IN gco2D Engine, + IN gctUINT32_PTR Addresses, + IN gctUINT32 AddressNum, + IN gctUINT32_PTR Strides, + IN gctUINT32 StrideNum, + IN gceTILING Tiling, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight +); + +gceSTATUS +gco2D_SetGenericTarget( + IN gco2D Engine, + IN gctUINT32_PTR Addresses, + IN gctUINT32 AddressNum, + IN gctUINT32_PTR Strides, + IN gctUINT32 StrideNum, + IN gceTILING Tiling, + IN gceSURF_FORMAT Format, + IN gceSURF_ROTATION Rotation, + IN gctUINT32 SurfaceWidth, + IN gctUINT32 SurfaceHeight +); + +gceSTATUS +gco2D_SetCurrentSourceIndex( + IN gco2D Engine, + IN gctUINT32 SrcIndex + ); + +gceSTATUS +gco2D_MultiSourceBlit( + IN gco2D Engine, + IN gctUINT32 SourceMask, + IN gcsRECT_PTR DestRect, + IN gctUINT32 RectCount + ); + +gceSTATUS +gco2D_SetROP( + IN gco2D Engine, + IN gctUINT8 FgRop, + IN gctUINT8 BgRop + ); + +gceSTATUS +gco2D_SetGdiStretchMode( + IN gco2D Engine, + IN gctBOOL Enable + ); + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_raster_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_rename.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_rename.h new file mode 100644 index 0000000..ed6718d --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_rename.h @@ -0,0 +1,250 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_rename_h_ +#define __gc_hal_rename_h_ + + +#if defined(_HAL2D_APPENDIX) + +#define _HAL2D_RENAME_2(api, appendix) api ## appendix +#define _HAL2D_RENAME_1(api, appendix) _HAL2D_RENAME_2(api, appendix) +#define gcmHAL2D(api) _HAL2D_RENAME_1(api, _HAL2D_APPENDIX) + + +#define gckOS_Construct gcmHAL2D(gckOS_Construct) +#define gckOS_Destroy gcmHAL2D(gckOS_Destroy) +#define gckOS_QueryVideoMemory gcmHAL2D(gckOS_QueryVideoMemory) +#define gckOS_Allocate gcmHAL2D(gckOS_Allocate) +#define gckOS_Free gcmHAL2D(gckOS_Free) +#define gckOS_AllocateMemory gcmHAL2D(gckOS_AllocateMemory) +#define gckOS_FreeMemory gcmHAL2D(gckOS_FreeMemory) +#define gckOS_AllocatePagedMemory gcmHAL2D(gckOS_AllocatePagedMemory) +#define gckOS_AllocatePagedMemoryEx gcmHAL2D(gckOS_AllocatePagedMemoryEx) +#define gckOS_LockPages gcmHAL2D(gckOS_LockPages) +#define gckOS_MapPages gcmHAL2D(gckOS_MapPages) +#define gckOS_UnlockPages gcmHAL2D(gckOS_UnlockPages) +#define gckOS_FreePagedMemory gcmHAL2D(gckOS_FreePagedMemory) +#define gckOS_AllocateNonPagedMemory gcmHAL2D(gckOS_AllocateNonPagedMemory) +#define gckOS_FreeNonPagedMemory gcmHAL2D(gckOS_FreeNonPagedMemory) +#define gckOS_AllocateContiguous gcmHAL2D(gckOS_AllocateContiguous) +#define gckOS_FreeContiguous gcmHAL2D(gckOS_FreeContiguous) +#define gckOS_GetPageSize gcmHAL2D(gckOS_GetPageSize) +#define gckOS_GetPhysicalAddress gcmHAL2D(gckOS_GetPhysicalAddress) +#define gckOS_GetPhysicalAddressProcess gcmHAL2D(gckOS_GetPhysicalAddressProcess) +#define gckOS_MapPhysical gcmHAL2D(gckOS_MapPhysical) +#define gckOS_UnmapPhysical gcmHAL2D(gckOS_UnmapPhysical) +#define gckOS_ReadRegister gcmHAL2D(gckOS_ReadRegister) +#define gckOS_WriteRegister gcmHAL2D(gckOS_WriteRegister) +#define gckOS_WriteMemory gcmHAL2D(gckOS_WriteMemory) +#define gckOS_MapMemory gcmHAL2D(gckOS_MapMemory) +#define gckOS_UnmapMemory gcmHAL2D(gckOS_UnmapMemory) +#define gckOS_UnmapMemoryEx gcmHAL2D(gckOS_UnmapMemoryEx) +#define gckOS_CreateMutex gcmHAL2D(gckOS_CreateMutex) +#define gckOS_DeleteMutex gcmHAL2D(gckOS_DeleteMutex) +#define gckOS_AcquireMutex gcmHAL2D(gckOS_AcquireMutex) +#define gckOS_ReleaseMutex gcmHAL2D(gckOS_ReleaseMutex) +#define gckOS_AtomicExchange gcmHAL2D(gckOS_AtomicExchange) +#define gckOS_AtomicExchangePtr gcmHAL2D(gckOS_AtomicExchangePtr) +#define gckOS_AtomConstruct gcmHAL2D(gckOS_AtomConstruct) +#define gckOS_AtomDestroy gcmHAL2D(gckOS_AtomDestroy) +#define gckOS_AtomGet gcmHAL2D(gckOS_AtomGet) +#define gckOS_AtomIncrement gcmHAL2D(gckOS_AtomIncrement) +#define gckOS_AtomDecrement gcmHAL2D(gckOS_AtomDecrement) +#define gckOS_Delay gcmHAL2D(gckOS_Delay) +#define gckOS_GetTime gcmHAL2D(gckOS_GetTime) +#define gckOS_MemoryBarrier gcmHAL2D(gckOS_MemoryBarrier) +#define gckOS_MapUserPointer gcmHAL2D(gckOS_MapUserPointer) +#define gckOS_UnmapUserPointer gcmHAL2D(gckOS_UnmapUserPointer) +#define gckOS_QueryNeedCopy gcmHAL2D(gckOS_QueryNeedCopy) +#define gckOS_CopyFromUserData gcmHAL2D(gckOS_CopyFromUserData) +#define gckOS_CopyToUserData gcmHAL2D(gckOS_CopyToUserData) +#define gckOS_MapUserPhysical gcmHAL2D(gckOS_MapUserPhysical) +#define gckOS_SuspendInterrupt gcmHAL2D(gckOS_SuspendInterrupt) +#define gckOS_ResumeInterrupt gcmHAL2D(gckOS_ResumeInterrupt) +#define gckOS_GetBaseAddress gcmHAL2D(gckOS_GetBaseAddress) +#define gckOS_MemCopy gcmHAL2D(gckOS_MemCopy) +#define gckOS_ZeroMemory gcmHAL2D(gckOS_ZeroMemory) +#define gckOS_DeviceControl gcmHAL2D(gckOS_DeviceControl) +#define gckOS_GetProcessID gcmHAL2D(gckOS_GetProcessID) +#define gckOS_GetThreadID gcmHAL2D(gckOS_GetThreadID) +#define gckOS_CreateSignal gcmHAL2D(gckOS_CreateSignal) +#define gckOS_DestroySignal gcmHAL2D(gckOS_DestroySignal) +#define gckOS_Signal gcmHAL2D(gckOS_Signal) +#define gckOS_WaitSignal gcmHAL2D(gckOS_WaitSignal) +#define gckOS_MapSignal gcmHAL2D(gckOS_MapSignal) +#define gckOS_MapUserMemory gcmHAL2D(gckOS_MapUserMemory) +#define gckOS_UnmapUserMemory gcmHAL2D(gckOS_UnmapUserMemory) +#define gckOS_CreateUserSignal gcmHAL2D(gckOS_CreateUserSignal) +#define gckOS_DestroyUserSignal gcmHAL2D(gckOS_DestroyUserSignal) +#define gckOS_WaitUserSignal gcmHAL2D(gckOS_WaitUserSignal) +#define gckOS_SignalUserSignal gcmHAL2D(gckOS_SignalUserSignal) +#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal) +#define gckOS_UserSignal gcmHAL2D(gckOS_UserSignal) +#define gckOS_CacheClean gcmHAL2D(gckOS_CacheClean) +#define gckOS_CacheFlush gcmHAL2D(gckOS_CacheFlush) +#define gckOS_SetDebugLevel gcmHAL2D(gckOS_SetDebugLevel) +#define gckOS_SetDebugZone gcmHAL2D(gckOS_SetDebugZone) +#define gckOS_SetDebugLevelZone gcmHAL2D(gckOS_SetDebugLevelZone) +#define gckOS_SetDebugZones gcmHAL2D(gckOS_SetDebugZones) +#define gckOS_SetDebugFile gcmHAL2D(gckOS_SetDebugFile) +#define gckOS_Broadcast gcmHAL2D(gckOS_Broadcast) +#define gckOS_SetGPUPower gcmHAL2D(gckOS_SetGPUPower) +#define gckOS_CreateSemaphore gcmHAL2D(gckOS_CreateSemaphore) +#define gckOS_DestroySemaphore gcmHAL2D(gckOS_DestroySemaphore) +#define gckOS_AcquireSemaphore gcmHAL2D(gckOS_AcquireSemaphore) +#define gckOS_ReleaseSemaphore gcmHAL2D(gckOS_ReleaseSemaphore) +#define gckHEAP_Construct gcmHAL2D(gckHEAP_Construct) +#define gckHEAP_Destroy gcmHAL2D(gckHEAP_Destroy) +#define gckHEAP_Allocate gcmHAL2D(gckHEAP_Allocate) +#define gckHEAP_Free gcmHAL2D(gckHEAP_Free) +#define gckHEAP_ProfileStart gcmHAL2D(gckHEAP_ProfileStart) +#define gckHEAP_ProfileEnd gcmHAL2D(gckHEAP_ProfileEnd) +#define gckHEAP_Test gcmHAL2D(gckHEAP_Test) +#define gckVIDMEM_Construct gcmHAL2D(gckVIDMEM_Construct) +#define gckVIDMEM_Destroy gcmHAL2D(gckVIDMEM_Destroy) +#define gckVIDMEM_Allocate gcmHAL2D(gckVIDMEM_Allocate) +#define gckVIDMEM_AllocateLinear gcmHAL2D(gckVIDMEM_AllocateLinear) +#define gckVIDMEM_Free gcmHAL2D(gckVIDMEM_Free) +#define gckVIDMEM_Lock gcmHAL2D(gckVIDMEM_Lock) +#define gckVIDMEM_Unlock gcmHAL2D(gckVIDMEM_Unlock) +#define gckVIDMEM_ConstructVirtual gcmHAL2D(gckVIDMEM_ConstructVirtual) +#define gckVIDMEM_DestroyVirtual gcmHAL2D(gckVIDMEM_DestroyVirtual) +#define gckKERNEL_Construct gcmHAL2D(gckKERNEL_Construct) +#define gckKERNEL_Destroy gcmHAL2D(gckKERNEL_Destroy) +#define gckKERNEL_Dispatch gcmHAL2D(gckKERNEL_Dispatch) +#define gckKERNEL_QueryVideoMemory gcmHAL2D(gckKERNEL_QueryVideoMemory) +#define gckKERNEL_GetVideoMemoryPool gcmHAL2D(gckKERNEL_GetVideoMemoryPool) +#define gckKERNEL_MapVideoMemory gcmHAL2D(gckKERNEL_MapVideoMemory) +#define gckKERNEL_UnmapVideoMemory gcmHAL2D(gckKERNEL_UnmapVideoMemory) +#define gckKERNEL_MapMemory gcmHAL2D(gckKERNEL_MapMemory) +#define gckKERNEL_UnmapMemory gcmHAL2D(gckKERNEL_UnmapMemory) +#define gckKERNEL_Notify gcmHAL2D(gckKERNEL_Notify) +#define gckKERNEL_QuerySettings gcmHAL2D(gckKERNEL_QuerySettings) +#define gckKERNEL_Recovery gcmHAL2D(gckKERNEL_Recovery) +#define gckKERNEL_OpenUserData gcmHAL2D(gckKERNEL_OpenUserData) +#define gckKERNEL_CloseUserData gcmHAL2D(gckKERNEL_CloseUserData) +#define gckHARDWARE_Construct gcmHAL2D(gckHARDWARE_Construct) +#define gckHARDWARE_Destroy gcmHAL2D(gckHARDWARE_Destroy) +#define gckHARDWARE_QuerySystemMemory gcmHAL2D(gckHARDWARE_QuerySystemMemory) +#define gckHARDWARE_BuildVirtualAddress gcmHAL2D(gckHARDWARE_BuildVirtualAddress) +#define gckHARDWARE_QueryCommandBuffer gcmHAL2D(gckHARDWARE_QueryCommandBuffer) +#define gckHARDWARE_WaitLink gcmHAL2D(gckHARDWARE_WaitLink) +#define gckHARDWARE_Execute gcmHAL2D(gckHARDWARE_Execute) +#define gckHARDWARE_End gcmHAL2D(gckHARDWARE_End) +#define gckHARDWARE_Nop gcmHAL2D(gckHARDWARE_Nop) +#define gckHARDWARE_Wait gcmHAL2D(gckHARDWARE_Wait) +#define gckHARDWARE_PipeSelect gcmHAL2D(gckHARDWARE_PipeSelect) +#define gckHARDWARE_Link gcmHAL2D(gckHARDWARE_Link) +#define gckHARDWARE_Event gcmHAL2D(gckHARDWARE_Event) +#define gckHARDWARE_QueryMemory gcmHAL2D(gckHARDWARE_QueryMemory) +#define gckHARDWARE_QueryChipIdentity gcmHAL2D(gckHARDWARE_QueryChipIdentity) +#define gckHARDWARE_QueryChipSpecs gcmHAL2D(gckHARDWARE_QueryChipSpecs) +#define gckHARDWARE_QueryShaderCaps gcmHAL2D(gckHARDWARE_QueryShaderCaps) +#define gckHARDWARE_ConvertFormat gcmHAL2D(gckHARDWARE_ConvertFormat) +#define gckHARDWARE_SplitMemory gcmHAL2D(gckHARDWARE_SplitMemory) +#define gckHARDWARE_AlignToTile gcmHAL2D(gckHARDWARE_AlignToTile) +#define gckHARDWARE_UpdateQueueTail gcmHAL2D(gckHARDWARE_UpdateQueueTail) +#define gckHARDWARE_ConvertLogical gcmHAL2D(gckHARDWARE_ConvertLogical) +#define gckHARDWARE_ConvertPhysical gcmHAL2D(gckHARDWARE_ConvertPhysical) +#define gckHARDWARE_Interrupt gcmHAL2D(gckHARDWARE_Interrupt) +#define gckHARDWARE_SetMMU gcmHAL2D(gckHARDWARE_SetMMU) +#define gckHARDWARE_FlushMMU gcmHAL2D(gckHARDWARE_FlushMMU) +#define gckHARDWARE_GetIdle gcmHAL2D(gckHARDWARE_GetIdle) +#define gckHARDWARE_Flush gcmHAL2D(gckHARDWARE_Flush) +#define gckHARDWARE_SetFastClear gcmHAL2D(gckHARDWARE_SetFastClear) +#define gckHARDWARE_ReadInterrupt gcmHAL2D(gckHARDWARE_ReadInterrupt) +#define gckHARDWARE_SetPowerManagementState gcmHAL2D(gckHARDWARE_SetPowerManagementState) +#define gckHARDWARE_QueryPowerManagementState gcmHAL2D(gckHARDWARE_QueryPowerManagementState) +#define gckHARDWARE_ProfileEngine2D gcmHAL2D(gckHARDWARE_ProfileEngine2D) +#define gckHARDWARE_InitializeHardware gcmHAL2D(gckHARDWARE_InitializeHardware) +#define gckHARDWARE_Reset gcmHAL2D(gckHARDWARE_Reset) +#define gckINTERRUPT_Construct gcmHAL2D(gckINTERRUPT_Construct) +#define gckINTERRUPT_Destroy gcmHAL2D(gckINTERRUPT_Destroy) +#define gckINTERRUPT_SetHandler gcmHAL2D(gckINTERRUPT_SetHandler) +#define gckINTERRUPT_Notify gcmHAL2D(gckINTERRUPT_Notify) +#define gckEVENT_Construct gcmHAL2D(gckEVENT_Construct) +#define gckEVENT_Destroy gcmHAL2D(gckEVENT_Destroy) +#define gckEVENT_AddList gcmHAL2D(gckEVENT_AddList) +#define gckEVENT_FreeNonPagedMemory gcmHAL2D(gckEVENT_FreeNonPagedMemory) +#define gckEVENT_FreeContiguousMemory gcmHAL2D(gckEVENT_FreeContiguousMemory) +#define gckEVENT_FreeVideoMemory gcmHAL2D(gckEVENT_FreeVideoMemory) +#define gckEVENT_Signal gcmHAL2D(gckEVENT_Signal) +#define gckEVENT_Unlock gcmHAL2D(gckEVENT_Unlock) +#define gckEVENT_Submit gcmHAL2D(gckEVENT_Submit) +#define gckEVENT_Commit gcmHAL2D(gckEVENT_Commit) +#define gckEVENT_Notify gcmHAL2D(gckEVENT_Notify) +#define gckEVENT_Interrupt gcmHAL2D(gckEVENT_Interrupt) +#define gckCOMMAND_Construct gcmHAL2D(gckCOMMAND_Construct) +#define gckCOMMAND_Destroy gcmHAL2D(gckCOMMAND_Destroy) +#define gckCOMMAND_EnterCommit gcmHAL2D(gckCOMMAND_EnterCommit) +#define gckCOMMAND_ExitCommit gcmHAL2D(gckCOMMAND_ExitCommit) +#define gckCOMMAND_Start gcmHAL2D(gckCOMMAND_Start) +#define gckCOMMAND_Stop gcmHAL2D(gckCOMMAND_Stop) +#define gckCOMMAND_Commit gcmHAL2D(gckCOMMAND_Commit) +#define gckCOMMAND_Reserve gcmHAL2D(gckCOMMAND_Reserve) +#define gckCOMMAND_Execute gcmHAL2D(gckCOMMAND_Execute) +#define gckCOMMAND_Stall gcmHAL2D(gckCOMMAND_Stall) +#define gckCOMMAND_Attach gcmHAL2D(gckCOMMAND_Attach) +#define gckCOMMAND_Detach gcmHAL2D(gckCOMMAND_Detach) +#define gckMMU_Construct gcmHAL2D(gckMMU_Construct) +#define gckMMU_Destroy gcmHAL2D(gckMMU_Destroy) +#define gckMMU_AllocatePages gcmHAL2D(gckMMU_AllocatePages) +#define gckMMU_FreePages gcmHAL2D(gckMMU_FreePages) +#define gckMMU_InsertNode gcmHAL2D(gckMMU_InsertNode) +#define gckMMU_RemoveNode gcmHAL2D(gckMMU_RemoveNode) +#define gckMMU_FreeHandleMemory gcmHAL2D(gckMMU_FreeHandleMemory) +#define gckMMU_Test gcmHAL2D(gckMMU_Test) +#define gckHARDWARE_QueryProfileRegisters gcmHAL2D(gckHARDWARE_QueryProfileRegisters) + + +#define FindMdlMap gcmHAL2D(FindMdlMap) +#define OnProcessExit gcmHAL2D(OnProcessExit) + +#define gckGALDEVICE_Destroy gcmHAL2D(gckGALDEVICE_Destroy) +#define gckOS_Print gcmHAL2D(gckOS_Print) +#define gckGALDEVICE_FreeMemory gcmHAL2D(gckGALDEVICE_FreeMemory) +#define gckGALDEVICE_AllocateMemory gcmHAL2D(gckGALDEVICE_AllocateMemory) +#define gckOS_DebugBreak gcmHAL2D(gckOS_DebugBreak) +#define gckGALDEVICE_Release_ISR gcmHAL2D(gckGALDEVICE_Release_ISR) +#define gckOS_Verify gcmHAL2D(gckOS_Verify) +#define gckCOMMAND_Release gcmHAL2D(gckCOMMAND_Release) +#define gckGALDEVICE_Stop gcmHAL2D(gckGALDEVICE_Stop) +#define gckGALDEVICE_Construct gcmHAL2D(gckGALDEVICE_Construct) +#define gckOS_DebugFatal gcmHAL2D(gckOS_DebugFatal) +#define gckOS_DebugTrace gcmHAL2D(gckOS_DebugTrace) +#define gckHARDWARE_GetBaseAddress gcmHAL2D(gckHARDWARE_GetBaseAddress) +#define gckGALDEVICE_Setup_ISR gcmHAL2D(gckGALDEVICE_Setup_ISR) +#define gckKERNEL_AttachProcess gcmHAL2D(gckKERNEL_AttachProcess) +#define gckKERNEL_AttachProcessEx gcmHAL2D(gckKERNEL_AttachProcessEx) +#define gckGALDEVICE_Start_Thread gcmHAL2D(gckGALDEVICE_Start_Thread) +#define gckHARDWARE_QueryIdle gcmHAL2D(gckHARDWARE_QueryIdle) +#define gckGALDEVICE_Start gcmHAL2D(gckGALDEVICE_Start) +#define gckOS_GetKernelLogical gcmHAL2D(gckOS_GetKernelLogical) +#define gckOS_DebugTraceZone gcmHAL2D(gckOS_DebugTraceZone) +#define gckGALDEVICE_Stop_Thread gcmHAL2D(gckGALDEVICE_Stop_Thread) +#define gckHARDWARE_NeedBaseAddress gcmHAL2D(gckHARDWARE_NeedBaseAddress) + +#endif + +#endif /* __gc_hal_rename_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_types.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_types.h new file mode 100644 index 0000000..e6d38c1 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_types.h @@ -0,0 +1,970 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_types_h_ +#define __gc_hal_types_h_ + +#include "gc_hal_version.h" +#include "gc_hal_options.h" + +#ifdef _WIN32 +#pragma warning(disable:4127) /* Conditional expression is constant (do { } + ** while(0)). */ +#pragma warning(disable:4100) /* Unreferenced formal parameter. */ +#pragma warning(disable:4204) /* Non-constant aggregate initializer (C99). */ +#pragma warning(disable:4131) /* Uses old-style declarator (for Bison and + ** Flex generated files). */ +#pragma warning(disable:4206) /* Translation unit is empty. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +** Platform macros. +*/ + +#if defined(__GNUC__) +# define gcdHAS_ELLIPSES 1 /* GCC always has it. */ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +# define gcdHAS_ELLIPSES 1 /* C99 has it. */ +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) +# define gcdHAS_ELLIPSES 1 /* MSVC 2007+ has it. */ +#elif defined(UNDER_CE) +#if UNDER_CE >= 600 +# define gcdHAS_ELLIPSES 1 +# else +# define gcdHAS_ELLIPSES 0 +# endif +#else +# error "gcdHAS_ELLIPSES: Platform could not be determined" +#endif + +/******************************************************************************\ +************************************ Keyword *********************************** +\******************************************************************************/ + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) +# define gcmINLINE inline /* C99 keyword. */ +#elif defined(__GNUC__) +# define gcmINLINE __inline__ /* GNU keyword. */ +#elif defined(_MSC_VER) || defined(UNDER_CE) +# define gcmINLINE __inline /* Internal keyword. */ +#else +# error "gcmINLINE: Platform could not be determined" +#endif + +/* Possible debug flags. */ +#define gcdDEBUG_NONE 0 +#define gcdDEBUG_ALL (1 << 0) +#define gcdDEBUG_FATAL (1 << 1) +#define gcdDEBUG_TRACE (1 << 2) +#define gcdDEBUG_BREAK (1 << 3) +#define gcdDEBUG_ASSERT (1 << 4) +#define gcdDEBUG_CODE (1 << 5) +#define gcdDEBUG_STACK (1 << 6) + +#define gcmIS_DEBUG(flag) ( gcdDEBUG & (flag | gcdDEBUG_ALL) ) + +#ifndef gcdDEBUG +#if (defined(DBG) && DBG) || defined(DEBUG) || defined(_DEBUG) +# define gcdDEBUG gcdDEBUG_ALL +# else +# define gcdDEBUG gcdDEBUG_NONE +# endif +#endif + +#ifdef _USRDLL +#ifdef _MSC_VER +#ifdef HAL_EXPORTS +# define HALAPI __declspec(dllexport) +# else +# define HALAPI __declspec(dllimport) +# endif +# define HALDECL __cdecl +# else +#ifdef HAL_EXPORTS +# define HALAPI +# else +# define HALAPI extern +# endif +# endif +#else +# define HALAPI +# define HALDECL +#endif + +/******************************************************************************\ +********************************** Common Types ******************************** +\******************************************************************************/ + +#define gcvFALSE 0 +#define gcvTRUE 1 + +#define gcvINFINITE ((gctUINT32) ~0U) + +#define gcvINVALID_HANDLE ((gctHANDLE) ~0U) + +typedef int gctBOOL; +typedef gctBOOL * gctBOOL_PTR; + +typedef int gctINT; +typedef signed char gctINT8; +typedef signed short gctINT16; +typedef signed int gctINT32; +typedef signed long long gctINT64; + +typedef gctINT * gctINT_PTR; +typedef gctINT8 * gctINT8_PTR; +typedef gctINT16 * gctINT16_PTR; +typedef gctINT32 * gctINT32_PTR; +typedef gctINT64 * gctINT64_PTR; + +typedef unsigned int gctUINT; +typedef unsigned char gctUINT8; +typedef unsigned short gctUINT16; +typedef unsigned int gctUINT32; +typedef unsigned long long gctUINT64; + +typedef gctUINT * gctUINT_PTR; +typedef gctUINT8 * gctUINT8_PTR; +typedef gctUINT16 * gctUINT16_PTR; +typedef gctUINT32 * gctUINT32_PTR; +typedef gctUINT64 * gctUINT64_PTR; + +typedef unsigned long gctSIZE_T; +typedef gctSIZE_T * gctSIZE_T_PTR; + +#ifdef __cplusplus +# define gcvNULL 0 +#else +# define gcvNULL ((void *) 0) +#endif + +typedef float gctFLOAT; +typedef signed int gctFIXED_POINT; +typedef float * gctFLOAT_PTR; + +typedef void * gctPHYS_ADDR; +typedef void * gctHANDLE; +typedef void * gctFILE; +typedef void * gctSIGNAL; +typedef void * gctWINDOW; +typedef void * gctIMAGE; + +typedef void * gctSEMAPHORE; + +typedef void * gctPOINTER; +typedef const void * gctCONST_POINTER; + +typedef char gctCHAR; +typedef char * gctSTRING; +typedef const char * gctCONST_STRING; + +typedef struct _gcsCOUNT_STRING +{ + gctSIZE_T Length; + gctCONST_STRING String; +} +gcsCOUNT_STRING; + +typedef union _gcuFLOAT_UINT32 +{ + gctFLOAT f; + gctUINT32 u; +} +gcuFLOAT_UINT32; + +/* Fixed point constants. */ +#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) +#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) +#define gcvONE_X ((gctFIXED_POINT) 0x00010000) +#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) +#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) + +/* Stringizing macro. */ +#define gcmSTRING(Value) #Value + +/******************************************************************************\ +******************************* Fixed Point Math ******************************* +\******************************************************************************/ + +#define gcmXMultiply(x1, x2) gcoMATH_MultiplyFixed(x1, x2) +#define gcmXDivide(x1, x2) gcoMATH_DivideFixed(x1, x2) +#define gcmXMultiplyDivide(x1, x2, x3) gcoMATH_MultiplyDivideFixed(x1, x2, x3) + +/* 2D Engine profile. */ +typedef struct _gcs2D_PROFILE +{ + /* Cycle count. + 32bit counter incremented every 2D clock cycle. + Wraps back to 0 when the counter overflows. + */ + gctUINT32 cycleCount; + + /* Pixels rendered by the 2D engine. + Resets to 0 every time it is read. */ + gctUINT32 pixelsRendered; +} +gcs2D_PROFILE; + +/* Macro to combine four characters into a Charcater Code. */ +#define gcmCC(c1, c2, c3, c4) \ +( \ + (char) (c1) \ + | \ + ((char) (c2) << 8) \ + | \ + ((char) (c3) << 16) \ + | \ + ((char) (c4) << 24) \ +) + +#define gcmPRINTABLE(c) ((((c) >= ' ') && ((c) <= '}')) ? ((c) != '%' ? (c) : ' ') : ' ') + +#define gcmCC_PRINT(cc) \ + gcmPRINTABLE((char) ( (cc) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 8) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 16) & 0xFF)), \ + gcmPRINTABLE((char) (((cc) >> 24) & 0xFF)) + +/******************************************************************************\ +****************************** Function Parameters ***************************** +\******************************************************************************/ + +#define IN +#define OUT +#define OPTIONAL + +/******************************************************************************\ +********************************* Status Codes ********************************* +\******************************************************************************/ + +typedef enum _gceSTATUS +{ + gcvSTATUS_OK = 0, + gcvSTATUS_FALSE = 0, + gcvSTATUS_TRUE = 1, + gcvSTATUS_NO_MORE_DATA = 2, + gcvSTATUS_CACHED = 3, + gcvSTATUS_MIPMAP_TOO_LARGE = 4, + gcvSTATUS_NAME_NOT_FOUND = 5, + gcvSTATUS_NOT_OUR_INTERRUPT = 6, + gcvSTATUS_MISMATCH = 7, + gcvSTATUS_MIPMAP_TOO_SMALL = 8, + gcvSTATUS_LARGER = 9, + gcvSTATUS_SMALLER = 10, + gcvSTATUS_CHIP_NOT_READY = 11, + gcvSTATUS_NEED_CONVERSION = 12, + gcvSTATUS_SKIP = 13, + gcvSTATUS_DATA_TOO_LARGE = 14, + gcvSTATUS_INVALID_CONFIG = 15, + gcvSTATUS_CHANGED = 16, + gcvSTATUS_NOT_SUPPORT_DITHER = 17, + gcvSTATUS_EXECUTED = 18, + gcvSTATUS_TERMINATE = 19, + + gcvSTATUS_INVALID_ARGUMENT = -1, + gcvSTATUS_INVALID_OBJECT = -2, + gcvSTATUS_OUT_OF_MEMORY = -3, + gcvSTATUS_MEMORY_LOCKED = -4, + gcvSTATUS_MEMORY_UNLOCKED = -5, + gcvSTATUS_HEAP_CORRUPTED = -6, + gcvSTATUS_GENERIC_IO = -7, + gcvSTATUS_INVALID_ADDRESS = -8, + gcvSTATUS_CONTEXT_LOSSED = -9, + gcvSTATUS_TOO_COMPLEX = -10, + gcvSTATUS_BUFFER_TOO_SMALL = -11, + gcvSTATUS_INTERFACE_ERROR = -12, + gcvSTATUS_NOT_SUPPORTED = -13, + gcvSTATUS_MORE_DATA = -14, + gcvSTATUS_TIMEOUT = -15, + gcvSTATUS_OUT_OF_RESOURCES = -16, + gcvSTATUS_INVALID_DATA = -17, + gcvSTATUS_INVALID_MIPMAP = -18, + gcvSTATUS_NOT_FOUND = -19, + gcvSTATUS_NOT_ALIGNED = -20, + gcvSTATUS_INVALID_REQUEST = -21, + gcvSTATUS_GPU_NOT_RESPONDING = -22, + gcvSTATUS_TIMER_OVERFLOW = -23, + gcvSTATUS_VERSION_MISMATCH = -24, + gcvSTATUS_LOCKED = -25, + gcvSTATUS_INTERRUPTED = -26, + gcvSTATUS_DEVICE = -27, + + /* Linker errors. */ + gcvSTATUS_GLOBAL_TYPE_MISMATCH = -1000, + gcvSTATUS_TOO_MANY_ATTRIBUTES = -1001, + gcvSTATUS_TOO_MANY_UNIFORMS = -1002, + gcvSTATUS_TOO_MANY_VARYINGS = -1003, + gcvSTATUS_UNDECLARED_VARYING = -1004, + gcvSTATUS_VARYING_TYPE_MISMATCH = -1005, + gcvSTATUS_MISSING_MAIN = -1006, + gcvSTATUS_NAME_MISMATCH = -1007, + gcvSTATUS_INVALID_INDEX = -1008, + gcvSTATUS_UNIFORM_TYPE_MISMATCH = -1009, +} +gceSTATUS; + +/******************************************************************************\ +********************************* Status Macros ******************************** +\******************************************************************************/ + +#define gcmIS_ERROR(status) (status < 0) +#define gcmNO_ERROR(status) (status >= 0) +#define gcmIS_SUCCESS(status) (status == gcvSTATUS_OK) + +/******************************************************************************\ +********************************* Field Macros ********************************* +\******************************************************************************/ + +#define __gcmSTART(reg_field) \ + (0 ? reg_field) + +#define __gcmEND(reg_field) \ + (1 ? reg_field) + +#define __gcmGETSIZE(reg_field) \ + (__gcmEND(reg_field) - __gcmSTART(reg_field) + 1) + +#define __gcmALIGN(data, reg_field) \ + (((gctUINT32) (data)) << __gcmSTART(reg_field)) + +#define __gcmMASK(reg_field) \ + ((gctUINT32) ((__gcmGETSIZE(reg_field) == 32) \ + ? ~0 \ + : (~(~0 << __gcmGETSIZE(reg_field))))) + +/******************************************************************************* +** +** gcmFIELDMASK +** +** Get aligned field mask. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +*/ +#define gcmFIELDMASK(reg, field) \ +( \ + __gcmALIGN(__gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmGETFIELD +** +** Extract the value of a field from specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +*/ +#define gcmGETFIELD(data, reg, field) \ +( \ + ((((gctUINT32) (data)) >> __gcmSTART(reg##_##field)) \ + & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** +** gcmSETFIELD +** +** Set the value of a field within specified data. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETFIELD(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN((gctUINT32) (value) \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmSETFIELDVALUE +** +** Set the value of a field within specified data with a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmSETFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) \ + & ~__gcmALIGN(__gcmMASK(reg##_##field), reg##_##field)) \ + | __gcmALIGN(reg##_##field##_##value \ + & __gcmMASK(reg##_##field), reg##_##field) \ +) + +/******************************************************************************* +** +** gcmGETMASKEDFIELDMASK +** +** Determine field mask of a masked field. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +*/ +#define gcmGETMASKEDFIELDMASK(reg, field) \ +( \ + gcmSETFIELD(0, reg, field, ~0) | \ + gcmSETFIELD(0, reg, MASK_ ## field, ~0) \ +) + +/******************************************************************************* +** +** gcmSETMASKEDFIELD +** +** Set the value of a masked field with specified data. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETMASKEDFIELD(reg, field, value) \ +( \ + gcmSETFIELD (~0, reg, field, value) & \ + gcmSETFIELDVALUE(~0, reg, MASK_ ## field, ENABLED) \ +) + +/******************************************************************************* +** +** gcmSETMASKEDFIELDVALUE +** +** Set the value of a masked field with specified data. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmSETMASKEDFIELDVALUE(reg, field, value) \ +( \ + gcmSETFIELDVALUE(~0, reg, field, value) & \ + gcmSETFIELDVALUE(~0, reg, MASK_ ## field, ENABLED) \ +) + +/******************************************************************************* +** +** gcmVERIFYFIELDVALUE +** +** Verify if the value of a field within specified data equals a +** predefined value. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Name of the value within the field. +*/ +#define gcmVERIFYFIELDVALUE(data, reg, field, value) \ +( \ + (((gctUINT32) (data)) >> __gcmSTART(reg##_##field) & \ + __gcmMASK(reg##_##field)) \ + == \ + (reg##_##field##_##value & __gcmMASK(reg##_##field)) \ +) + +/******************************************************************************* +** Bit field macros. +*/ + +#define __gcmSTARTBIT(Field) \ + ( 1 ? Field ) + +#define __gcmBITSIZE(Field) \ + ( 0 ? Field ) + +#define __gcmBITMASK(Field) \ +( \ + (1 << __gcmBITSIZE(Field)) - 1 \ +) + +#define gcmGETBITS(Value, Type, Field) \ +( \ + ( ((Type) (Value)) >> __gcmSTARTBIT(Field) ) \ + & \ + __gcmBITMASK(Field) \ +) + +#define gcmSETBITS(Value, Type, Field, NewValue) \ +( \ + ( ((Type) (Value)) \ + & ~(__gcmBITMASK(Field) << __gcmSTARTBIT(Field)) \ + ) \ + | \ + ( ( ((Type) (NewValue)) \ + & __gcmBITMASK(Field) \ + ) << __gcmSTARTBIT(Field) \ + ) \ +) + +/******************************************************************************* +** +** gcmISINREGRANGE +** +** Verify whether the specified address is in the register range. +** +** ARGUMENTS: +** +** Address Address to be verified. +** Name Name of a register. +*/ + +#define gcmISINREGRANGE(Address, Name) \ +( \ + ((Address & (~0U << Name ## _LSB)) == (Name ## _Address >> 2)) \ +) + +/******************************************************************************* +** +** A set of macros to aid state loading. +** +** ARGUMENTS: +** +** CommandBuffer Pointer to a gcoCMDBUF object. +** StateDelta Pointer to a gcsSTATE_DELTA state delta structure. +** Memory Destination memory pointer of gctUINT32_PTR type. +** PartOfContext Whether or not the state is a part of the context. +** FixedPoint Whether or not the state is of the fixed point format. +** Count Number of consecutive states to be loaded. +** Address State address. +** Data Data to be set to the state. +*/ + +/*----------------------------------------------------------------------------*/ + +#if gcmIS_DEBUG(gcdDEBUG_CODE) + +# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) \ + CommandBuffer->lastLoadStatePtr = Memory; \ + CommandBuffer->lastLoadStateAddress = Address; \ + CommandBuffer->lastLoadStateCount = Count + +# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) \ + gcmASSERT( \ + (gctUINT) (Memory - CommandBuffer->lastLoadStatePtr - 1) \ + == \ + (gctUINT) (Address - CommandBuffer->lastLoadStateAddress) \ + ); \ + \ + gcmASSERT(CommandBuffer->lastLoadStateCount > 0); \ + \ + CommandBuffer->lastLoadStateCount -= 1 + +# define gcmVERIFYLOADSTATEDONE(CommandBuffer) \ + gcmASSERT(CommandBuffer->lastLoadStateCount == 0) + +#else + +# define gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count) +# define gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address) +# define gcmVERIFYLOADSTATEDONE(CommandBuffer) + +#endif + +#if gcdSECURE_USER + +# define gcmDEFINESECUREUSER() \ + gctUINT __secure_user_offset__; \ + gctUINT32_PTR __secure_user_hintArray__; + +# define gcmBEGINSECUREUSER() \ + __secure_user_offset__ = reserve->lastOffset; \ + \ + __secure_user_hintArray__ = reserve->hintArrayTail + +# define gcmENDSECUREUSER() \ + reserve->hintArrayTail = __secure_user_hintArray__ + +# define gcmSKIPSECUREUSER() \ + __secure_user_offset__ += gcmSIZEOF(gctUINT32) + +# define gcmUPDATESECUREUSER() \ + *__secure_user_hintArray__ = __secure_user_offset__; \ + \ + __secure_user_offset__ += gcmSIZEOF(gctUINT32); \ + __secure_user_hintArray__ += 1 + +#else + +# define gcmDEFINESECUREUSER() +# define gcmBEGINSECUREUSER() +# define gcmENDSECUREUSER() +# define gcmSKIPSECUREUSER() +# define gcmUPDATESECUREUSER() + +#endif + +/*----------------------------------------------------------------------------*/ + +#if gcdDUMP +# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data) \ + if (FixedPoint) \ + { \ + gcmDUMP(gcvNULL, "@[state.x 0x%04X 0x%08X]", \ + Address, Data \ + ); \ + } \ + else \ + { \ + gcmDUMP(gcvNULL, "@[state 0x%04X 0x%08X]", \ + Address, Data \ + ); \ + } +#else +# define gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, Data) +#endif + +/*----------------------------------------------------------------------------*/ + +#define gcmDEFINESTATEBUFFER(CommandBuffer, StateDelta, Memory, ReserveSize) \ + gcmDEFINESECUREUSER() \ + gctSIZE_T ReserveSize; \ + gcoCMDBUF CommandBuffer; \ + gctUINT32_PTR Memory; \ + gcsSTATE_DELTA_PTR StateDelta + +#define gcmBEGINSTATEBUFFER(Hardware, CommandBuffer, StateDelta, Memory, ReserveSize) \ +{ \ + gcmONERROR(gcoBUFFER_Reserve( \ + Hardware->buffer, ReserveSize, gcvTRUE, &CommandBuffer \ + )); \ + \ + Memory = (gctUINT32_PTR) CommandBuffer->lastReserve; \ + \ + StateDelta = Hardware->delta; \ + \ + gcmBEGINSECUREUSER(); \ +} + +#define gcmENDSTATEBUFFER(CommandBuffer, Memory, ReserveSize) \ +{ \ + gcmENDSECUREUSER(); \ + \ + gcmASSERT( \ + ((gctUINT8_PTR) CommandBuffer->lastReserve) + ReserveSize \ + == \ + (gctUINT8_PTR) Memory \ + ); \ +} + +/*----------------------------------------------------------------------------*/ + +#define gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, Count) \ +{ \ + gcmASSERT(((Memory - (gctUINT32_PTR) CommandBuffer->lastReserve) & 1) == 0); \ + \ + gcmVERIFYLOADSTATEDONE(CommandBuffer); \ + \ + gcmSTORELOADSTATE(CommandBuffer, Memory, Address, Count); \ + \ + *Memory++ \ + = gcmSETFIELDVALUE(0, AQ_COMMAND_LOAD_STATE_COMMAND, OPCODE, LOAD_STATE) \ + | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, FLOAT, FixedPoint) \ + | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, COUNT, Count) \ + | gcmSETFIELD (0, AQ_COMMAND_LOAD_STATE_COMMAND, ADDRESS, Address); \ + \ + gcmSKIPSECUREUSER(); \ +} + +#define gcmENDSTATEBATCH(CommandBuffer, Memory) \ +{ \ + gcmVERIFYLOADSTATEDONE(CommandBuffer); \ + \ + gcmASSERT(((Memory - (gctUINT32_PTR) CommandBuffer->lastReserve) & 1) == 0); \ +} + +/*----------------------------------------------------------------------------*/ + +#define gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \ + Address, Data) \ +{ \ + gctUINT32 __temp_data32__; \ + \ + gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ + \ + __temp_data32__ = Data; \ + \ + *Memory++ = __temp_data32__; \ + \ + gcoHARDWARE_UpdateDelta( \ + StateDelta, FixedPoint, Address, 0, __temp_data32__ \ + ); \ + \ + gcmDUMPSTATEDATA(StateDelta, FixedPoint, Address, __temp_data32__); \ + \ + gcmUPDATESECUREUSER(); \ +} + +#define gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data) \ +{ \ + gctUINT32 __temp_data32__; \ + \ + gcmVERIFYLOADSTATE(CommandBuffer, Memory, Address); \ + \ + __temp_data32__ = Data; \ + \ + *Memory++ = __temp_data32__; \ + \ + gcmDUMPSTATEDATA(StateDelta, gcvFALSE, Address, __temp_data32__); \ + \ + gcmSKIPSECUREUSER(); \ +} + +#define gcmSETFILLER(CommandBuffer, Memory) \ +{ \ + gcmVERIFYLOADSTATEDONE(CommandBuffer); \ + \ + Memory += 1; \ + \ + gcmSKIPSECUREUSER(); \ +} + +/*----------------------------------------------------------------------------*/ + +#define gcmSETSINGLESTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \ + Address, Data) \ +{ \ + gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ + gcmSETSTATEDATA(StateDelta, CommandBuffer, Memory, FixedPoint, \ + Address, Data); \ + gcmENDSTATEBATCH(CommandBuffer, Memory); \ +} + +#define gcmSETSINGLECTRLSTATE(StateDelta, CommandBuffer, Memory, FixedPoint, \ + Address, Data) \ +{ \ + gcmBEGINSTATEBATCH(CommandBuffer, Memory, FixedPoint, Address, 1); \ + gcmSETCTRLSTATE(StateDelta, CommandBuffer, Memory, Address, Data); \ + gcmENDSTATEBATCH(CommandBuffer, Memory); \ +} + + +/******************************************************************************* +** +** gcmSETSTARTDECOMMAND +** +** Form a START_DE command. +** +** ARGUMENTS: +** +** Memory Destination memory pointer of gctUINT32_PTR type. +** Count Number of the rectangles. +*/ + +#define gcmSETSTARTDECOMMAND(Memory, Count) \ +{ \ + *Memory++ \ + = gcmSETFIELDVALUE(0, AQ_COMMAND_START_DE_COMMAND, OPCODE, START_DE) \ + | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, COUNT, Count) \ + | gcmSETFIELD (0, AQ_COMMAND_START_DE_COMMAND, DATA_COUNT, 0); \ + \ + *Memory++ = 0xDEADDEED; \ +} + +/******************************************************************************\ +******************************** Ceiling Macro ******************************** +\******************************************************************************/ +#define gcmCEIL(x) ((x - (gctUINT32)x) == 0 ? (gctUINT32)x : (gctUINT32)x + 1) + +/******************************************************************************\ +******************************** Min/Max Macros ******************************** +\******************************************************************************/ + +#define gcmMIN(x, y) (((x) <= (y)) ? (x) : (y)) +#define gcmMAX(x, y) (((x) >= (y)) ? (x) : (y)) +#define gcmCLAMP(x, min, max) (((x) < (min)) ? (min) : \ + ((x) > (max)) ? (max) : (x)) +#define gcmABS(x) (((x) < 0) ? -(x) : (x)) +#define gcmNEG(x) (((x) < 0) ? (x) : -(x)) + +/******************************************************************************* +** +** gcmPTR2INT +** +** Convert a pointer to an integer value. +** +** ARGUMENTS: +** +** p Pointer value. +*/ +#if defined(_WIN32) || (defined(__LP64__) && __LP64__) +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (gctUINT64) (p) \ + ) +#else +# define gcmPTR2INT(p) \ + ( \ + (gctUINT32) (p) \ + ) +#endif + +/******************************************************************************* +** +** gcmINT2PTR +** +** Convert an integer value into a pointer. +** +** ARGUMENTS: +** +** v Integer value. +*/ +#ifdef __LP64__ +# define gcmINT2PTR(i) \ + ( \ + (gctPOINTER) (gctINT64) (i) \ + ) +#else +# define gcmINT2PTR(i) \ + ( \ + (gctPOINTER) (i) \ + ) +#endif + +/******************************************************************************* +** +** gcmOFFSETOF +** +** Compute the byte offset of a field inside a structure. +** +** ARGUMENTS: +** +** s Structure name. +** field Field name. +*/ +#define gcmOFFSETOF(s, field) \ +( \ + gcmPTR2INT(& (((struct s *) 0)->field)) \ +) + +/******************************************************************************* +***** Database ****************************************************************/ + +typedef struct _gcsDATABASE_COUNTERS +{ + /* Number of currently allocated bytes. */ + gctSIZE_T bytes; + + /* Maximum number of bytes allocated (memory footprint). */ + gctSIZE_T maxBytes; + + /* Total number of bytes allocated. */ + gctSIZE_T totalBytes; +} +gcsDATABASE_COUNTERS; + +typedef struct _gcuDATABASE_INFO +{ + /* Counters. */ + gcsDATABASE_COUNTERS counters; + + /* Time value. */ + gctUINT64 time; +} +gcuDATABASE_INFO; + +/******************************************************************************* +***** Frame database **********************************************************/ + +/* gcsHAL_FRAME_INFO */ +typedef struct _gcsHAL_FRAME_INFO +{ + /* Current timer tick. */ + OUT gctUINT64 ticks; + + /* Bandwidth counters. */ + OUT gctUINT readBytes8[8]; + OUT gctUINT writeBytes8[8]; + + /* Counters. */ + OUT gctUINT cycles[8]; + OUT gctUINT idleCycles[8]; + OUT gctUINT mcCycles[8]; + OUT gctUINT readRequests[8]; + OUT gctUINT writeRequests[8]; + + /* 3D counters. */ + OUT gctUINT vertexCount; + OUT gctUINT primitiveCount; + OUT gctUINT rejectedPrimitives; + OUT gctUINT culledPrimitives; + OUT gctUINT clippedPrimitives; + OUT gctUINT outPrimitives; + OUT gctUINT inPrimitives; + OUT gctUINT culledQuadCount; + OUT gctUINT totalQuadCount; + OUT gctUINT quadCount; + OUT gctUINT totalPixelCount; + + /* PE counters. */ + OUT gctUINT colorKilled[8]; + OUT gctUINT colorDrawn[8]; + OUT gctUINT depthKilled[8]; + OUT gctUINT depthDrawn[8]; + + /* Shader counters. */ + OUT gctUINT shaderCycles; + OUT gctUINT vsInstructionCount; + OUT gctUINT vsTextureCount; + OUT gctUINT psInstructionCount; + OUT gctUINT psTextureCount; + + /* Texture counters. */ + OUT gctUINT bilinearRequests; + OUT gctUINT trilinearRequests; + OUT gctUINT txBytes8; + OUT gctUINT txHitCount; + OUT gctUINT txMissCount; +} +gcsHAL_FRAME_INFO; + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_types_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_version.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_version.h new file mode 100644 index 0000000..83db422 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_version.h @@ -0,0 +1,39 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_version_h_ +#define __gc_hal_version_h_ + +#define gcvVERSION_MAJOR 4 + +#define gcvVERSION_MINOR 6 + +#define gcvVERSION_PATCH 6 + +#define gcvVERSION_BUILD 1381 + +#define gcvVERSION_DATE __DATE__ + +#define gcvVERSION_TIME __TIME__ + +#endif /* __gc_hal_version_h_ */ diff --git a/kernel_drivers/v4/hal/kernel/inc/gc_hal_vg.h b/kernel_drivers/v4/hal/kernel/inc/gc_hal_vg.h new file mode 100644 index 0000000..2060170 --- /dev/null +++ b/kernel_drivers/v4/hal/kernel/inc/gc_hal_vg.h @@ -0,0 +1,933 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + + + +#ifndef __gc_hal_vg_h_ +#define __gc_hal_vg_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "gc_hal_rename.h" +#include "gc_hal_types.h" +#include "gc_hal_enum.h" +#include "gc_hal_base.h" + +#if gcdENABLE_VG + +/* Thread routine type. */ +#if defined(LINUX) + typedef gctINT gctTHREADFUNCRESULT; + typedef gctPOINTER gctTHREADFUNCPARAMETER; +# define gctTHREADFUNCTYPE +#elif defined(WIN32) + typedef gctUINT gctTHREADFUNCRESULT; + typedef gctPOINTER gctTHREADFUNCPARAMETER; +# define gctTHREADFUNCTYPE __stdcall +#elif defined(__QNXNTO__) + typedef void * gctTHREADFUNCRESULT; + typedef gctPOINTER gctTHREADFUNCPARAMETER; +# define gctTHREADFUNCTYPE +#endif + +typedef gctTHREADFUNCRESULT (gctTHREADFUNCTYPE * gctTHREADFUNC) ( + gctTHREADFUNCPARAMETER ThreadParameter + ); + + +#if defined(gcvDEBUG) +# undef gcvDEBUG +#endif + +#define gcdFORCE_DEBUG 0 +#define gcdFORCE_MESSAGES 0 + + +#if DBG || defined(DEBUG) || defined(_DEBUG) || gcdFORCE_DEBUG +# define gcvDEBUG 1 +#else +# define gcvDEBUG 0 +#endif + +#define _gcmERROR_RETURN(prefix, func) \ + status = func; \ + if (gcmIS_ERROR(status)) \ + { \ + prefix##PRINT_VERSION(); \ + prefix##TRACE(gcvLEVEL_ERROR, \ + #prefix "ERR_RETURN: status=%d(%s) @ %s(%d)", \ + status, gcoOS_DebugStatus2Name(status), __FUNCTION__, __LINE__); \ + return status; \ + } \ + do { } while (gcvFALSE) + +#define gcmERROR_RETURN(func) _gcmERROR_RETURN(gcm, func) + +#define gcmLOG_LOCATION() + +#define gcmkIS_ERROR(status) (status < 0) + +#define gcmALIGNDOWN(n, align) \ +( \ + (n) & ~((align) - 1) \ +) + +#define gcmIS_VALID_INDEX(Index, Array) \ + (((gctUINT) (Index)) < gcmCOUNTOF(Array)) + + +#define gcmIS_NAN(x) \ +( \ + ((* (gctUINT32_PTR) &(x)) & 0x7FFFFFFF) == 0x7FFFFFFF \ +) + +#define gcmLERP(v1, v2, w) \ + ((v1) * (w) + (v2) * (1.0f - (w))) + +#define gcmINTERSECT(Start1, Start2, Length) \ + (gcmABS((Start1) - (Start2)) < (Length)) + +/******************************************************************************* +** +** gcmERR_GOTO +** +** Prints a message and terminates the current loop on error. +** +** ASSUMPTIONS: +** +** 'status' variable of gceSTATUS type must be defined. +** +** ARGUMENTS: +** +** Function +** Function to evaluate. +*/ + +#define gcmERR_GOTO(Function) \ + status = Function; \ + if (gcmIS_ERROR(status)) \ + { \ + gcmTRACE( \ + gcvLEVEL_ERROR, \ + "gcmERR_GOTO: status=%d @ line=%d in function %s.\n", \ + status, __LINE__, __FUNCTION__ \ + ); \ + goto ErrorHandler; \ + } + +#if gcvDEBUG || gcdFORCE_MESSAGES +# define gcmVERIFY_BOOLEAN(Expression) \ + gcmASSERT( \ + ( (Expression) == gcvFALSE ) || \ + ( (Expression) == gcvTRUE ) \ + ) +#else +# define gcmVERIFY_BOOLEAN(Expression) +#endif + +/******************************************************************************* +** +** gcmVERIFYFIELDFIT +** +** Verify whether the value fits in the field. +** +** ARGUMENTS: +** +** data Data value. +** reg Name of register. +** field Name of field within register. +** value Value for field. +*/ +#define gcmVERIFYFIELDFIT(reg, field, value) \ + gcmASSERT( \ + (value) <= gcmFIELDMAX(reg, field) \ + ) +/******************************************************************************* +** +** gcmFIELDMAX +** +** Get field maximum value. +** +** ARGUMENTS: +** +** reg Name of register. +** field Name of field within register. +*/ +#define gcmFIELDMAX(reg, field) \ +( \ + (gctUINT32) \ + ( \ + (__gcmGETSIZE(reg##_##field) == 32) \ + ? ~0 \ + : (~(~0 << __gcmGETSIZE(reg##_##field))) \ + ) \ +) + + +/* ANSI C does not have the 'f' functions, define replacements here. */ +#define gcmSINF(x) ((gctFLOAT) sin(x)) +#define gcmCOSF(x) ((gctFLOAT) cos(x)) +#define gcmASINF(x) ((gctFLOAT) asin(x)) +#define gcmACOSF(x) ((gctFLOAT) acos(x)) +#define gcmSQRTF(x) ((gctFLOAT) sqrt(x)) +#define gcmFABSF(x) ((gctFLOAT) fabs(x)) +#define gcmFMODF(x, y) ((gctFLOAT) fmod((x), (y))) +#define gcmCEILF(x) ((gctFLOAT) ceil(x)) +#define gcmFLOORF(x) ((gctFLOAT) floor(x)) + + + +/* Fixed point constants. */ +#define gcvZERO_X ((gctFIXED_POINT) 0x00000000) +#define gcvHALF_X ((gctFIXED_POINT) 0x00008000) +#define gcvONE_X ((gctFIXED_POINT) 0x00010000) +#define gcvNEGONE_X ((gctFIXED_POINT) 0xFFFF0000) +#define gcvTWO_X ((gctFIXED_POINT) 0x00020000) + +/* Integer constants. */ +#define gcvMAX_POS_INT ((gctINT) 0x7FFFFFFF) +#define gcvMAX_NEG_INT ((gctINT) 0x80000000) + +/* Float constants. */ +#define gcvMAX_POS_FLOAT ((gctFLOAT) 3.4028235e+038) +#define gcvMAX_NEG_FLOAT ((gctFLOAT) -3.4028235e+038) + +/******************************************************************************\ +***************************** Miscellaneous Macro ****************************** +\******************************************************************************/ + +#define gcmKB2BYTES(Kilobyte) \ +( \ + (Kilobyte) << 10 \ +) + +#define gcmMB2BYTES(Megabyte) \ +( \ + (Megabyte) << 20 \ +) + +#define gcmMAT(Matrix, Row, Column) \ +( \ + (Matrix) [(Row) * 3 + (Column)] \ +) + +#define gcmMAKE2CHAR(Char1, Char2) \ +( \ + ((gctUINT16) (gctUINT8) (Char1) << 0) | \ + ((gctUINT16) (gctUINT8) (Char2) << 8) \ +) + +#define gcmMAKE4CHAR(Char1, Char2, Char3, Char4) \ +( \ + ((gctUINT32)(gctUINT8) (Char1) << 0) | \ + ((gctUINT32)(gctUINT8) (Char2) << 8) | \ + ((gctUINT32)(gctUINT8) (Char3) << 16) | \ + ((gctUINT32)(gctUINT8) (Char4) << 24) \ +) + +/* some platforms need to fix the physical address for HW to access*/ +#ifdef __QNXNTO__ + +gcmINLINE static gctUINT32 _qnxFixAddress(gctUINT32 Address) +{ + gctUINT32 baseAddress = 0; + + if (gcmIS_ERROR(gcoOS_GetBaseAddress(gcvNULL, &baseAddress))) + { + baseAddress = 0; + } + + return Address + baseAddress; +} + +#define gcmFIXADDRESS _qnxFixAddress + +gcmINLINE static gctUINT32 _qnxkFixAddress(gctUINT32 Address) +{ + extern unsigned long baseAddress; + return Address + baseAddress; +} + +#define gcmkFIXADDRESS _qnxkFixAddress + +#else + +#define gcmFIXADDRESS(address) \ +(\ + (address)\ +) + +#define gcmkFIXADDRESS(address) \ +(\ + (address)\ +) + +#endif + +/******************************************************************************\ +****************************** Kernel Debug Macro ****************************** +\******************************************************************************/ + +/* Set signal to signaled state for specified process. */ +gceSTATUS +gckOS_SetSignal( + IN gckOS Os, + IN gctHANDLE Process, + IN gctSIGNAL Signal + ); + +/* Return the kernel logical pointer for the given physical one. */ +gceSTATUS +gckOS_GetKernelLogical( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ); + +/* Return the kernel logical pointer for the given physical one. */ +gceSTATUS +gckOS_GetKernelLogicalEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ); + +/*----------------------------------------------------------------------------*/ +/*----------------------------- Semaphore Object -----------------------------*/ + +/* Increment the value of a semaphore. */ +gceSTATUS +gckOS_IncrementSemaphore( + IN gckOS Os, + IN gctSEMAPHORE Semaphore + ); + +/* Decrement the value of a semaphore (waiting might occur). */ +gceSTATUS +gckOS_DecrementSemaphore( + IN gckOS Os, + IN gctSEMAPHORE Semaphore + ); + + +/*----------------------------------------------------------------------------*/ +/*------------------------------- Thread Object ------------------------------*/ + +/* Start a thread. */ +gceSTATUS +gckOS_StartThread( + IN gckOS Os, + IN gctTHREADFUNC ThreadFunction, + IN gctPOINTER ThreadParameter, + OUT gctTHREAD * Thread + ); + +/* Stop a thread. */ +gceSTATUS +gckOS_StopThread( + IN gckOS Os, + IN gctTHREAD Thread + ); + +/* Verify whether the thread is still running. */ +gceSTATUS +gckOS_VerifyThread( + IN gckOS Os, + IN gctTHREAD Thread + ); + + +/* Construct a new gckVGKERNEL object. */ +gceSTATUS +gckVGKERNEL_Construct( + IN gckOS Os, + IN gctPOINTER Context, + IN gckKERNEL inKernel, + OUT gckVGKERNEL * Kernel + ); + +/* Destroy an gckVGKERNEL object. */ +gceSTATUS +gckVGKERNEL_Destroy( + IN gckVGKERNEL Kernel + ); + +/* Allocate linear video memory. */ +gceSTATUS +gckKERNEL_AllocateLinearMemory( + IN gckKERNEL Kernel, + IN OUT gcePOOL * Pool, + IN gctSIZE_T Bytes, + IN gctSIZE_T Alignment, + IN gceSURF_TYPE Type, + OUT gcuVIDMEM_NODE_PTR * Node + ); + +/* Unmap memory. */ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ); + +/* Dispatch a user-level command. */ +gceSTATUS +gckVGKERNEL_Dispatch( + IN gckKERNEL Kernel, + IN gctBOOL FromUser, + IN OUT struct _gcsHAL_INTERFACE * Interface + ); + +/* Query command buffer requirements. */ +gceSTATUS +gckKERNEL_QueryCommandBuffer( + IN gckKERNEL Kernel, + OUT gcsCOMMAND_BUFFER_INFO_PTR Information + ); + +#if gcdDYNAMIC_MAP_RESERVED_MEMORY +gceSTATUS +gckOS_MapReservedMemoryToKernel( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctINT Bytes, + IN OUT gctPOINTER *Virtual + ); + +gceSTATUS +gckOS_UnmapReservedMemoryFromKernel( + IN gctPOINTER Virtual + ); +#endif + +/******************************************************************************\ +******************************* gckVGHARDWARE Object ****************************** +\******************************************************************************/ + +/* Construct a new gckVGHARDWARE object. */ +gceSTATUS +gckVGHARDWARE_Construct( + IN gckOS Os, + OUT gckVGHARDWARE * Hardware + ); + +/* Destroy an gckVGHARDWARE object. */ +gceSTATUS +gckVGHARDWARE_Destroy( + IN gckVGHARDWARE Hardware + ); + +/* Query system memory requirements. */ +gceSTATUS +gckVGHARDWARE_QuerySystemMemory( + IN gckVGHARDWARE Hardware, + OUT gctSIZE_T * SystemSize, + OUT gctUINT32 * SystemBaseAddress + ); + +/* Build virtual address. */ +gceSTATUS +gckVGHARDWARE_BuildVirtualAddress( + IN gckVGHARDWARE Hardware, + IN gctUINT32 Index, + IN gctUINT32 Offset, + OUT gctUINT32 * Address + ); + +/* Kickstart the command processor. */ +gceSTATUS +gckVGHARDWARE_Execute( + IN gckVGHARDWARE Hardware, + IN gctUINT32 Address, + IN gctSIZE_T Count + ); + +/* Query the available memory. */ +gceSTATUS +gckVGHARDWARE_QueryMemory( + IN gckVGHARDWARE Hardware, + OUT gctSIZE_T * InternalSize, + OUT gctUINT32 * InternalBaseAddress, + OUT gctUINT32 * InternalAlignment, + OUT gctSIZE_T * ExternalSize, + OUT gctUINT32 * ExternalBaseAddress, + OUT gctUINT32 * ExternalAlignment, + OUT gctUINT32 * HorizontalTileSize, + OUT gctUINT32 * VerticalTileSize + ); + +/* Query the identity of the hardware. */ +gceSTATUS +gckVGHARDWARE_QueryChipIdentity( + IN gckVGHARDWARE Hardware, + OUT gceCHIPMODEL* ChipModel, + OUT gctUINT32* ChipRevision, + OUT gctUINT32* ChipFeatures, + OUT gctUINT32* ChipMinorFeatures, + OUT gctUINT32* ChipMinorFeatures1 + ); + +/* Convert an API format. */ +gceSTATUS +gckVGHARDWARE_ConvertFormat( + IN gckVGHARDWARE Hardware, + IN gceSURF_FORMAT Format, + OUT gctUINT32 * BitsPerPixel, + OUT gctUINT32 * BytesPerTile + ); + +/* Split a harwdare specific address into API stuff. */ +gceSTATUS +gckVGHARDWARE_SplitMemory( + IN gckVGHARDWARE Hardware, + IN gctUINT32 Address, + OUT gcePOOL * Pool, + OUT gctUINT32 * Offset + ); + +/* Align size to tile boundary. */ +gceSTATUS +gckVGHARDWARE_AlignToTile( + IN gckVGHARDWARE Hardware, + IN gceSURF_TYPE Type, + IN OUT gctUINT32_PTR Width, + IN OUT gctUINT32_PTR Height + ); + +/* Convert logical address to hardware specific address. */ +gceSTATUS +gckVGHARDWARE_ConvertLogical( + IN gckVGHARDWARE Hardware, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ); + +/* Program MMU. */ +gceSTATUS +gckVGHARDWARE_SetMMU( + IN gckVGHARDWARE Hardware, + IN gctPOINTER Logical + ); + +/* Flush the MMU. */ +gceSTATUS +gckVGHARDWARE_FlushMMU( + IN gckVGHARDWARE Hardware + ); + +/* Get idle register. */ +gceSTATUS +gckVGHARDWARE_GetIdle( + IN gckVGHARDWARE Hardware, + OUT gctUINT32 * Data + ); + +/* Flush the caches. */ +gceSTATUS +gckVGHARDWARE_Flush( + IN gckVGHARDWARE Hardware, + IN gceKERNEL_FLUSH Flush, + IN gctPOINTER Logical, + IN OUT gctSIZE_T * Bytes + ); + +/* Enable/disable fast clear. */ +gceSTATUS +gckVGHARDWARE_SetFastClear( + IN gckVGHARDWARE Hardware, + IN gctINT Enable + ); + +gceSTATUS +gckVGHARDWARE_ReadInterrupt( + IN gckVGHARDWARE Hardware, + OUT gctUINT32_PTR IDs + ); + +/* Power management. */ +gceSTATUS +gckVGHARDWARE_SetPowerManagementState( + IN gckVGHARDWARE Hardware, + IN gceCHIPPOWERSTATE State + ); + +gceSTATUS +gckVGHARDWARE_QueryPowerManagementState( + IN gckVGHARDWARE Hardware, + OUT gceCHIPPOWERSTATE* State + ); + +gceSTATUS +gckVGHARDWARE_SetPowerOffTimeout( + IN gckVGHARDWARE Hardware, + IN gctUINT32 Timeout + ); + +gceSTATUS +gckVGHARDWARE_QueryPowerOffTimeout( + IN gckVGHARDWARE Hardware, + OUT gctUINT32* Timeout + ); + +gceSTATUS +gckVGHARDWARE_QueryIdle( + IN gckVGHARDWARE Hardware, + OUT gctBOOL_PTR IsIdle + ); +/******************************************************************************\ +*************************** Command Buffer Structures ************************** +\******************************************************************************/ + +/* Vacant command buffer marker. */ +#define gcvVACANT_BUFFER ((gcsCOMPLETION_SIGNAL_PTR) (1)) + +/* Command buffer header. */ +typedef struct _gcsCMDBUFFER * gcsCMDBUFFER_PTR; +typedef struct _gcsCMDBUFFER +{ + /* Pointer to the completion signal. */ + gcsCOMPLETION_SIGNAL_PTR completion; + + /* The user sets this to the node of the container buffer whitin which + this particular command buffer resides. The kernel sets this to the + node of the internally allocated buffer. */ + gcuVIDMEM_NODE_PTR node; + + /* Command buffer hardware address. */ + gctUINT32 address; + + /* The offset of the buffer from the beginning of the header. */ + gctUINT32 bufferOffset; + + /* Size of the area allocated for the data portion of this particular + command buffer (headers and tail reserves are excluded). */ + gctSIZE_T size; + + /* Offset into the buffer [0..size]; reflects exactly how much data has + been put into the command buffer. */ + gctUINT offset; + + /* The number of command units in the buffer for the hardware to + execute. */ + gctSIZE_T dataCount; + + /* MANAGED BY : user HAL (gcoBUFFER object). + USED BY : user HAL (gcoBUFFER object). + Points to the immediate next allocated command buffer. */ + gcsCMDBUFFER_PTR nextAllocated; + + /* MANAGED BY : user layers (HAL and drivers). + USED BY : kernel HAL (gcoBUFFER object). + Points to the next subbuffer if any. A family of subbuffers are chained + together and are meant to be executed inseparably as a unit. Meaning + that context switching cannot occur while a chain of subbuffers is being + executed. */ + gcsCMDBUFFER_PTR nextSubBuffer; +} +gcsCMDBUFFER; + +/* Command queue element. */ +typedef struct _gcsVGCMDQUEUE +{ + /* Pointer to the command buffer header. */ + gcsCMDBUFFER_PTR commandBuffer; + + /* Dynamic vs. static command buffer state. */ + gctBOOL dynamic; +} +gcsVGCMDQUEUE; + +/* Context map entry. */ +typedef struct _gcsVGCONTEXT_MAP +{ + /* State index. */ + gctUINT32 index; + + /* New state value. */ + gctUINT32 data; + + /* Points to the next entry in the mod list. */ + gcsVGCONTEXT_MAP_PTR next; +} +gcsVGCONTEXT_MAP; + +/* gcsVGCONTEXT structure that holds the current context. */ +typedef struct _gcsVGCONTEXT +{ + /* Context ID. */ + gctUINT64 id; + + /* State caching ebable flag. */ + gctBOOL stateCachingEnabled; + + /* Current pipe. */ + gctUINT32 currentPipe; + + /* State map/mod buffer. */ + gctSIZE_T mapFirst; + gctSIZE_T mapLast; +#ifdef __QNXNTO__ + gctSIZE_T mapContainerSize; +#endif + gcsVGCONTEXT_MAP_PTR mapContainer; + gcsVGCONTEXT_MAP_PTR mapPrev; + gcsVGCONTEXT_MAP_PTR mapCurr; + gcsVGCONTEXT_MAP_PTR firstPrevMap; + gcsVGCONTEXT_MAP_PTR firstCurrMap; + + /* Main context buffer. */ + gcsCMDBUFFER_PTR header; + gctUINT32_PTR buffer; + + /* Completion signal. */ + gctHANDLE process; + gctSIGNAL signal; + +#if defined(__QNXNTO__) + gctINT32 coid; + gctINT32 rcvid; +#endif +} +gcsVGCONTEXT; + +/* User space task header. */ +typedef struct _gcsTASK * gcsTASK_PTR; +typedef struct _gcsTASK +{ + /* Pointer to the next task for the same interrupt in user space. */ + gcsTASK_PTR next; + + /* Size of the task data that immediately follows the structure. */ + gctUINT size; + + /* Task data starts here. */ + /* ... */ +} +gcsTASK; + +/* User space task master table entry. */ +typedef struct _gcsTASK_MASTER_ENTRY * gcsTASK_MASTER_ENTRY_PTR; +typedef struct _gcsTASK_MASTER_ENTRY +{ + /* Pointers to the head and to the tail of the task chain. */ + gcsTASK_PTR head; + gcsTASK_PTR tail; +} +gcsTASK_MASTER_ENTRY; + +/* User space task master table entry. */ +typedef struct _gcsTASK_MASTER_TABLE +{ + /* Table with one entry per block. */ + gcsTASK_MASTER_ENTRY table[gcvBLOCK_COUNT]; + + /* The total number of tasks sckeduled. */ + gctUINT count; + + /* The total size of event data in bytes. */ + gctUINT size; + +#if defined(__QNXNTO__) + gctINT32 coid; + gctINT32 rcvid; +#endif +} +gcsTASK_MASTER_TABLE; + +/******************************************************************************\ +***************************** gckVGINTERRUPT Object ****************************** +\******************************************************************************/ + +typedef struct _gckVGINTERRUPT * gckVGINTERRUPT; + +typedef gceSTATUS (* gctINTERRUPT_HANDLER)( + IN gckVGKERNEL Kernel + ); + +gceSTATUS +gckVGINTERRUPT_Construct( + IN gckVGKERNEL Kernel, + OUT gckVGINTERRUPT * Interrupt + ); + +gceSTATUS +gckVGINTERRUPT_Destroy( + IN gckVGINTERRUPT Interrupt + ); + +gceSTATUS +gckVGINTERRUPT_Enable( + IN gckVGINTERRUPT Interrupt, + IN OUT gctINT32_PTR Id, + IN gctINTERRUPT_HANDLER Handler + ); + +gceSTATUS +gckVGINTERRUPT_Disable( + IN gckVGINTERRUPT Interrupt, + IN gctINT32 Id + ); + +#ifndef __QNXNTO__ + +gceSTATUS +gckVGINTERRUPT_Enque( + IN gckVGINTERRUPT Interrupt + ); + +#else + +gceSTATUS +gckVGINTERRUPT_Enque( + IN gckVGINTERRUPT Interrupt, + OUT gckOS *Os, + OUT gctSEMAPHORE *Semaphore + ); + +#endif + +gceSTATUS +gckVGINTERRUPT_DumpState( + IN gckVGINTERRUPT Interrupt + ); + + +/******************************************************************************\ +******************************* gckVGCOMMAND Object ******************************* +\******************************************************************************/ + +typedef struct _gckVGCOMMAND * gckVGCOMMAND; + +/* Construct a new gckVGCOMMAND object. */ +gceSTATUS +gckVGCOMMAND_Construct( + IN gckVGKERNEL Kernel, + IN gctUINT TaskGranularity, + IN gctUINT QueueSize, + OUT gckVGCOMMAND * Command + ); + +/* Destroy an gckVGCOMMAND object. */ +gceSTATUS +gckVGCOMMAND_Destroy( + IN gckVGCOMMAND Command + ); + +/* Query command buffer attributes. */ +gceSTATUS +gckVGCOMMAND_QueryCommandBuffer( + IN gckVGCOMMAND Command, + OUT gcsCOMMAND_BUFFER_INFO_PTR Information + ); + +/* Allocate a command queue. */ +gceSTATUS +gckVGCOMMAND_Allocate( + IN gckVGCOMMAND Command, + IN gctSIZE_T Size, + OUT gcsCMDBUFFER_PTR * CommandBuffer, + OUT gctPOINTER * Data + ); + +/* Release memory held by the command queue. */ +gceSTATUS +gckVGCOMMAND_Free( + IN gckVGCOMMAND Command, + IN gcsCMDBUFFER_PTR CommandBuffer + ); + +/* Schedule the command queue for execution. */ +gceSTATUS +gckVGCOMMAND_Execute( + IN gckVGCOMMAND Command, + IN gcsCMDBUFFER_PTR CommandBuffer + ); + +/* Commit a buffer to the command queue. */ +gceSTATUS +gckVGCOMMAND_Commit( + IN gckVGCOMMAND Command, + IN gcsVGCONTEXT_PTR Context, + IN gcsVGCMDQUEUE_PTR Queue, + IN gctUINT EntryCount, + IN gcsTASK_MASTER_TABLE_PTR TaskTable + ); + +/******************************************************************************\ +********************************* gckVGMMU Object ******************************** +\******************************************************************************/ + +typedef struct _gckVGMMU * gckVGMMU; + +/* Construct a new gckVGMMU object. */ +gceSTATUS +gckVGMMU_Construct( + IN gckVGKERNEL Kernel, + IN gctSIZE_T MmuSize, + OUT gckVGMMU * Mmu + ); + +/* Destroy an gckVGMMU object. */ +gceSTATUS +gckVGMMU_Destroy( + IN gckVGMMU Mmu + ); + +/* Allocate pages inside the MMU. */ +gceSTATUS +gckVGMMU_AllocatePages( + IN gckVGMMU Mmu, + IN gctSIZE_T PageCount, + OUT gctPOINTER * PageTable, + OUT gctUINT32 * Address + ); + +/* Remove a page table from the MMU. */ +gceSTATUS +gckVGMMU_FreePages( + IN gckVGMMU Mmu, + IN gctPOINTER PageTable, + IN gctSIZE_T PageCount + ); + +/* Set the MMU page with info. */ +gceSTATUS +gckVGMMU_SetPage( + IN gckVGMMU Mmu, + IN gctUINT32 PageAddress, + IN gctUINT32 *PageEntry + ); + +#endif /* gcdENABLE_VG */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __gc_hal_h_ */ diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_debug.h b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_debug.h new file mode 100644 index 0000000..5bbc893 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_debug.h @@ -0,0 +1,100 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_debug_h_ +#define __gc_hal_kernel_debug_h_ + +#include <gc_hal_kernel_linux.h> +#include <linux/spinlock.h> +#include <linux/time.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************\ +****************************** OS-dependent Macros ***************************** +\******************************************************************************/ + +typedef va_list gctARGUMENTS; + +#define gcmkARGUMENTS_START(Arguments, Pointer) \ + va_start(Arguments, Pointer) + +#define gcmkARGUMENTS_END(Arguments) \ + va_end(Arguments) + +#define gcmkDECLARE_LOCK(__spinLock__) \ + static DEFINE_SPINLOCK(__spinLock__); + +#define gcmkLOCKSECTION(__spinLock__) \ + spin_lock(&__spinLock__) + +#define gcmkUNLOCKSECTION(__spinLock__) \ + spin_unlock(&__spinLock__) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +# define gcmkGETPROCESSID() \ + task_tgid_vnr(current) +#else +# define gcmkGETPROCESSID() \ + current->tgid +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +# define gcmkGETTHREADID() \ + task_pid_vnr(current) +#else +# define gcmkGETTHREADID() \ + current->pid +#endif + +#define gcmkOUTPUT_STRING(String) \ + printk(String); \ + touch_softlockup_watchdog() + +#define gcmkSPRINTF(Destination, Size, Message, Value) \ + snprintf(Destination, Size, Message, Value) + +#define gcmkSPRINTF2(Destination, Size, Message, Value1, Value2) \ + snprintf(Destination, Size, Message, Value1, Value2) + +#define gcmkSPRINTF3(Destination, Size, Message, Value1, Value2, Value3) \ + snprintf(Destination, Size, Message, Value1, Value2, Value3) + +#define gcmkVSPRINTF(Destination, Size, Message, Arguments) \ + vsnprintf(Destination, Size, Message, *(va_list *) &Arguments) + +#define gcmkSTRCAT(Destination, Size, String) \ + strncat(Destination, String, Size) + +/* If not zero, forces data alignment in the variable argument list + by its individual size. */ +#define gcdALIGNBYSIZE 1 + +#ifdef __cplusplus +} +#endif + +#endif /* __gc_hal_kernel_debug_h_ */ diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.c b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.c new file mode 100644 index 0000000..44a519b --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.c @@ -0,0 +1,1525 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" +#include <linux/pagemap.h> +#include <linux/seq_file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/slab.h> + +#define _GC_OBJ_ZONE gcvZONE_DEVICE + +#ifdef FLAREON + static struct dove_gpio_irq_handler gc500_handle; +#endif + +#define gcmIS_CORE_PRESENT(Device, Core) (Device->irqLines[Core] > 0) + +/******************************************************************************\ +*************************** Memory Allocation Wrappers ************************* +\******************************************************************************/ + +static gceSTATUS +_AllocateMemory( + IN gckGALDEVICE Device, + IN gctSIZE_T Bytes, + OUT gctPOINTER *Logical, + OUT gctPHYS_ADDR *Physical, + OUT gctUINT32 *PhysAddr + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Device=0x%x Bytes=%lu", Device, Bytes); + + gcmkVERIFY_ARGUMENT(Device != NULL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + gcmkVERIFY_ARGUMENT(Physical != NULL); + gcmkVERIFY_ARGUMENT(PhysAddr != NULL); + + gcmkONERROR(gckOS_AllocateContiguous( + Device->os, gcvFALSE, &Bytes, Physical, Logical + )); + + *PhysAddr = ((PLINUX_MDL)*Physical)->dmaHandle - Device->baseAddress; + + /* Success. */ + gcmkFOOTER_ARG( + "*Logical=0x%x *Physical=0x%x *PhysAddr=0x%08x", + *Logical, *Physical, *PhysAddr + ); + + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_FreeMemory( + IN gckGALDEVICE Device, + IN gctPOINTER Logical, + IN gctPHYS_ADDR Physical) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Device=0x%x Logical=0x%x Physical=0x%x", + Device, Logical, Physical); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + status = gckOS_FreeContiguous( + Device->os, Physical, Logical, + ((PLINUX_MDL) Physical)->numPages * PAGE_SIZE + ); + + gcmkFOOTER(); + return status; +} + + + +/******************************************************************************\ +******************************* Interrupt Handler ****************************** +\******************************************************************************/ +static irqreturn_t isrRoutine(int irq, void *ctxt) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = (gckGALDEVICE) ctxt; + + /* Call kernel interrupt notification. */ + status = gckKERNEL_Notify(device->kernels[gcvCORE_MAJOR], gcvNOTIFY_INTERRUPT, gcvTRUE); + + if (gcmIS_SUCCESS(status)) + { + device->dataReadys[gcvCORE_MAJOR] = gcvTRUE; + + up(&device->semas[gcvCORE_MAJOR]); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int threadRoutine(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting isr Thread with extension=%p", + device); + + for (;;) + { + static int down; + + down = down_interruptible(&device->semas[gcvCORE_MAJOR]); + if (down); /*To make gcc4.6 happy*/ + device->dataReadys[gcvCORE_MAJOR] = gcvFALSE; + + if (device->killThread == gcvTRUE) + { + /* The daemon exits. */ + while (!kthread_should_stop()) + { + gckOS_Delay(device->os, 1); + } + + return 0; + } + + gckKERNEL_Notify(device->kernels[gcvCORE_MAJOR], gcvNOTIFY_INTERRUPT, gcvFALSE); + } +} + +static irqreturn_t isrRoutine2D(int irq, void *ctxt) +{ + gceSTATUS status; + gckGALDEVICE device; + + device = (gckGALDEVICE) ctxt; + + /* Call kernel interrupt notification. */ + status = gckKERNEL_Notify(device->kernels[gcvCORE_2D], gcvNOTIFY_INTERRUPT, gcvTRUE); + + if (gcmIS_SUCCESS(status)) + { + device->dataReadys[gcvCORE_2D] = gcvTRUE; + + up(&device->semas[gcvCORE_2D]); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int threadRoutine2D(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting isr Thread with extension=%p", + device); + + for (;;) + { + static int down; + + down = down_interruptible(&device->semas[gcvCORE_2D]); + if (down); /*To make gcc4.6 happy*/ + device->dataReadys[gcvCORE_2D] = gcvFALSE; + + if (device->killThread == gcvTRUE) + { + /* The daemon exits. */ + while (!kthread_should_stop()) + { + gckOS_Delay(device->os, 1); + } + + return 0; + } + + gckKERNEL_Notify(device->kernels[gcvCORE_2D], gcvNOTIFY_INTERRUPT, gcvFALSE); + } +} + +static irqreturn_t isrRoutineVG(int irq, void *ctxt) +{ +#if gcdENABLE_VG + gceSTATUS status; + gckGALDEVICE device; + + device = (gckGALDEVICE) ctxt; + + /* Serve the interrupt. */ + status = gckVGINTERRUPT_Enque(device->kernels[gcvCORE_VG]->vg->interrupt); + + /* Determine the return value. */ + return (status == gcvSTATUS_NOT_OUR_INTERRUPT) + ? IRQ_RETVAL(0) + : IRQ_RETVAL(1); +#else + return IRQ_NONE; +#endif +} + +static int threadRoutineVG(void *ctxt) +{ + gckGALDEVICE device = (gckGALDEVICE) ctxt; + + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Starting isr Thread with extension=%p", + device); + + for (;;) + { + static int down; + + down = down_interruptible(&device->semas[gcvCORE_VG]); + if (down); /*To make gcc4.6 happy*/ + device->dataReadys[gcvCORE_VG] = gcvFALSE; + + if (device->killThread == gcvTRUE) + { + /* The daemon exits. */ + while (!kthread_should_stop()) + { + gckOS_Delay(device->os, 1); + } + + return 0; + } + + gckKERNEL_Notify(device->kernels[gcvCORE_VG], gcvNOTIFY_INTERRUPT, gcvFALSE); + } +} + +/******************************************************************************\ +******************************* gckGALDEVICE Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckGALDEVICE_Construct +** +** Constructor. +** +** INPUT: +** +** OUTPUT: +** +** gckGALDEVICE * Device +** Pointer to a variable receiving the gckGALDEVICE object pointer on +** success. +*/ +gceSTATUS +gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctINT IrqLine2D, + IN gctUINT32 RegisterMemBase2D, + IN gctSIZE_T RegisterMemSize2D, + IN gctINT IrqLineVG, + IN gctUINT32 RegisterMemBaseVG, + IN gctSIZE_T RegisterMemSizeVG, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 PhysBaseAddr, + IN gctUINT32 PhysSize, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ) +{ + gctUINT32 internalBaseAddress = 0, internalAlignment = 0; + gctUINT32 externalBaseAddress = 0, externalAlignment = 0; + gctUINT32 horizontalTileSize, verticalTileSize; + struct resource* mem_region; + gctUINT32 physAddr; + gctUINT32 physical; + gckGALDEVICE device; + gceSTATUS status; + gctINT32 i; + gceHARDWARE_TYPE type; + gckDB sharedDB = gcvNULL; + + gcmkHEADER_ARG("IrqLine=%d RegisterMemBase=0x%08x RegisterMemSize=%u " + "IrqLine2D=%d RegisterMemBase2D=0x%08x RegisterMemSize2D=%u " + "IrqLineVG=%d RegisterMemBaseVG=0x%08x RegisterMemSizeVG=%u " + "ContiguousBase=0x%08x ContiguousSize=%lu BankSize=%lu " + "FastClear=%d Compression=%d PhysBaseAddr=0x%x PhysSize=%d Signal=%d", + IrqLine, RegisterMemBase, RegisterMemSize, + IrqLine2D, RegisterMemBase2D, RegisterMemSize2D, + IrqLineVG, RegisterMemBaseVG, RegisterMemSizeVG, + ContiguousBase, ContiguousSize, BankSize, FastClear, Compression, + PhysBaseAddr, PhysSize, Signal); + + /* Allocate device structure. */ + device = kmalloc(sizeof(struct _gckGALDEVICE), GFP_KERNEL | __GFP_NOWARN); + + if (!device) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + memset(device, 0, sizeof(struct _gckGALDEVICE)); + + if (IrqLine != -1) + { + device->requestedRegisterMemBases[gcvCORE_MAJOR] = RegisterMemBase; + device->requestedRegisterMemSizes[gcvCORE_MAJOR] = RegisterMemSize; + } + + if (IrqLine2D != -1) + { + device->requestedRegisterMemBases[gcvCORE_2D] = RegisterMemBase2D; + device->requestedRegisterMemSizes[gcvCORE_2D] = RegisterMemSize2D; + } + + if (IrqLineVG != -1) + { + device->requestedRegisterMemBases[gcvCORE_VG] = RegisterMemBaseVG; + device->requestedRegisterMemSizes[gcvCORE_VG] = RegisterMemSizeVG; + } + + device->requestedContiguousBase = 0; + device->requestedContiguousSize = 0; + + + for (i = 0; i < gcdCORE_COUNT; i++) + { + physical = device->requestedRegisterMemBases[i]; + + /* Set up register memory region. */ + if (physical != 0) + { + mem_region = request_mem_region( + physical, device->requestedRegisterMemSizes[i], "galcore register region" + ); + +#if 0 + if (mem_region == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Failed to claim %lu bytes @ 0x%08X\n", + __FUNCTION__, __LINE__, + physical, device->requestedRegisterMemSizes[i] + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } +#endif + + device->registerBases[i] = (gctPOINTER) ioremap_nocache( + physical, device->requestedRegisterMemSizes[i]); + + if (device->registerBases[i] == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Unable to map %ld bytes @ 0x%08X\n", + __FUNCTION__, __LINE__, + physical, device->requestedRegisterMemSizes[i] + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + physical += device->requestedRegisterMemSizes[i]; + } + else + { + device->registerBases[i] = gcvNULL; + } + } + + /* Set the base address */ + device->baseAddress = PhysBaseAddr; + + /* Construct the gckOS object. */ + gcmkONERROR(gckOS_Construct(device, &device->os)); + + if (IrqLine != -1) + { + /* Construct the gckKERNEL object. */ + gcmkONERROR(gckKERNEL_Construct( + device->os, gcvCORE_MAJOR, device, + gcvNULL, &device->kernels[gcvCORE_MAJOR])); + + sharedDB = device->kernels[gcvCORE_MAJOR]->db; + + /* Initialize core mapping */ + for (i = 0; i < 8; i++) + { + device->coreMapping[i] = gcvCORE_MAJOR; + } + + /* Setup the ISR manager. */ + gcmkONERROR(gckHARDWARE_SetIsrManager( + device->kernels[gcvCORE_MAJOR]->hardware, + (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR, + (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR, + device + )); + + gcmkONERROR(gckHARDWARE_SetFastClear( + device->kernels[gcvCORE_MAJOR]->hardware, FastClear, Compression + )); + + +#if COMMAND_PROCESSOR_VERSION == 1 + /* Start the command queue. */ + gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_MAJOR]->command)); +#endif + } + else + { + device->kernels[gcvCORE_MAJOR] = gcvNULL; + } + + if (IrqLine2D != -1) + { + gcmkONERROR(gckKERNEL_Construct( + device->os, gcvCORE_2D, device, + sharedDB, &device->kernels[gcvCORE_2D])); + + if (sharedDB == gcvNULL) sharedDB = device->kernels[gcvCORE_2D]->db; + + /* Verify the hardware type */ + gcmkONERROR(gckHARDWARE_GetType(device->kernels[gcvCORE_2D]->hardware, &type)); + + if (type != gcvHARDWARE_2D) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Unexpected hardware type: %d\n", + __FUNCTION__, __LINE__, + type + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Initialize core mapping */ + if (device->kernels[gcvCORE_MAJOR] == gcvNULL) + { + for (i = 0; i < 8; i++) + { + device->coreMapping[i] = gcvCORE_2D; + } + } + else + { + device->coreMapping[gcvHARDWARE_2D] = gcvCORE_2D; + } + + /* Setup the ISR manager. */ + gcmkONERROR(gckHARDWARE_SetIsrManager( + device->kernels[gcvCORE_2D]->hardware, + (gctISRMANAGERFUNC) gckGALDEVICE_Setup_ISR_2D, + (gctISRMANAGERFUNC) gckGALDEVICE_Release_ISR_2D, + device + )); + +#if COMMAND_PROCESSOR_VERSION == 1 + /* Start the command queue. */ + gcmkONERROR(gckCOMMAND_Start(device->kernels[gcvCORE_2D]->command)); +#endif + } + else + { + device->kernels[gcvCORE_2D] = gcvNULL; + } + + if (IrqLineVG != -1) + { +#if gcdENABLE_VG + gcmkONERROR(gckKERNEL_Construct( + device->os, gcvCORE_VG, device, + sharedDB, &device->kernels[gcvCORE_VG])); + /* Initialize core mapping */ + if (device->kernels[gcvCORE_MAJOR] == gcvNULL + && device->kernels[gcvCORE_2D] == gcvNULL + ) + { + for (i = 0; i < 8; i++) + { + device->coreMapping[i] = gcvCORE_VG; + } + } + else + { + device->coreMapping[gcvHARDWARE_VG] = gcvCORE_VG; + } + +#endif + } + else + { + device->kernels[gcvCORE_VG] = gcvNULL; + } + + /* Initialize the ISR. */ + device->irqLines[gcvCORE_MAJOR] = IrqLine; + device->irqLines[gcvCORE_2D] = IrqLine2D; + device->irqLines[gcvCORE_VG] = IrqLineVG; + + /* Initialize the kernel thread semaphores. */ + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (device->irqLines[i] != -1) sema_init(&device->semas[i], 0); + } + + device->signal = Signal; + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (device->kernels[i] != gcvNULL) break; + } + + if (i == gcdCORE_COUNT) gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + /* Query the ceiling of the system memory. */ + gcmkONERROR(gckVGHARDWARE_QuerySystemMemory( + device->kernels[i]->vg->hardware, + &device->systemMemorySize, + &device->systemMemoryBaseAddress + )); + /* query the amount of video memory */ + gcmkONERROR(gckVGHARDWARE_QueryMemory( + device->kernels[i]->vg->hardware, + &device->internalSize, &internalBaseAddress, &internalAlignment, + &device->externalSize, &externalBaseAddress, &externalAlignment, + &horizontalTileSize, &verticalTileSize + )); + } + else +#endif + { + /* Query the ceiling of the system memory. */ + gcmkONERROR(gckHARDWARE_QuerySystemMemory( + device->kernels[i]->hardware, + &device->systemMemorySize, + &device->systemMemoryBaseAddress + )); + + /* query the amount of video memory */ + gcmkONERROR(gckHARDWARE_QueryMemory( + device->kernels[i]->hardware, + &device->internalSize, &internalBaseAddress, &internalAlignment, + &device->externalSize, &externalBaseAddress, &externalAlignment, + &horizontalTileSize, &verticalTileSize + )); + } + + + /* Set up the internal memory region. */ + if (device->internalSize > 0) + { + status = gckVIDMEM_Construct( + device->os, + internalBaseAddress, device->internalSize, internalAlignment, + 0, &device->internalVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, disable internal heap. */ + device->internalSize = 0; + } + else + { + /* Map internal memory. */ + device->internalLogical + = (gctPOINTER) ioremap_nocache(physical, device->internalSize); + + if (device->internalLogical == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + device->internalPhysical = (gctPHYS_ADDR) physical; + physical += device->internalSize; + } + } + + if (device->externalSize > 0) + { + /* create the external memory heap */ + status = gckVIDMEM_Construct( + device->os, + externalBaseAddress, device->externalSize, externalAlignment, + 0, &device->externalVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, disable internal heap. */ + device->externalSize = 0; + } + else + { + /* Map external memory. */ + device->externalLogical + = (gctPOINTER) ioremap_nocache(physical, device->externalSize); + + if (device->externalLogical == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + device->externalPhysical = (gctPHYS_ADDR) physical; + physical += device->externalSize; + } + } + + /* set up the contiguous memory */ + device->contiguousSize = ContiguousSize; + + if (ContiguousSize > 0) + { + if (ContiguousBase == 0) + { + while (device->contiguousSize > 0) + { + /* Allocate contiguous memory. */ + status = _AllocateMemory( + device, + device->contiguousSize, + &device->contiguousBase, + &device->contiguousPhysical, + &physAddr + ); + + if (gcmIS_SUCCESS(status)) + { + status = gckVIDMEM_Construct( + device->os, + physAddr | device->systemMemoryBaseAddress, + device->contiguousSize, + 64, + BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_SUCCESS(status)) + { + break; + } + + gcmkONERROR(_FreeMemory( + device, + device->contiguousBase, + device->contiguousPhysical + )); + + device->contiguousBase = gcvNULL; + device->contiguousPhysical = gcvNULL; + } + + if (device->contiguousSize <= (4 << 20)) + { + device->contiguousSize = 0; + } + else + { + device->contiguousSize -= (4 << 20); + } + } + } + else + { + /* Create the contiguous memory heap. */ + status = gckVIDMEM_Construct( + device->os, + (ContiguousBase - device->baseAddress) | device->systemMemoryBaseAddress, + ContiguousSize, + 64, BankSize, + &device->contiguousVidMem + ); + + if (gcmIS_ERROR(status)) + { + /* Error, disable contiguous memory pool. */ + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + } + else + { + mem_region = request_mem_region( + ContiguousBase, ContiguousSize, "galcore managed memory" + ); + +#if 0 + if (mem_region == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Failed to claim %ld bytes @ 0x%08X\n", + __FUNCTION__, __LINE__, + ContiguousSize, ContiguousBase + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } +#endif + + device->requestedContiguousBase = ContiguousBase; + device->requestedContiguousSize = ContiguousSize; + +#if !gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG + if (gcmIS_CORE_PRESENT(device, gcvCORE_VG)) + { + device->contiguousBase +#if gcdPAGED_MEMORY_CACHEABLE + = (gctPOINTER) ioremap_cached(ContiguousBase, ContiguousSize); +#else + = (gctPOINTER) ioremap_nocache(ContiguousBase, ContiguousSize); +#endif + if (device->contiguousBase == gcvNULL) + { + device->contiguousVidMem = gcvNULL; + device->contiguousSize = 0; + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } +#endif + + device->contiguousPhysical = (gctPHYS_ADDR) ContiguousBase; + device->contiguousSize = ContiguousSize; + device->contiguousMapped = gcvTRUE; + } + } + } + + /* Return pointer to the device. */ + * Device = device; + + gcmkFOOTER_ARG("*Device=0x%x", * Device); + return gcvSTATUS_OK; + +OnError: + /* Roll back. */ + gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); + + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Destroy +** +** Class destructor. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Destroy( + gckGALDEVICE Device) +{ + gctINT i; + gceSTATUS status = gcvSTATUS_OK; + + gcmkHEADER_ARG("Device=0x%x", Device); + + if (Device != gcvNULL) + { + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (Device->kernels[i] != gcvNULL) + { + /* Destroy the gckKERNEL object. */ + gcmkVERIFY_OK(gckKERNEL_Destroy(Device->kernels[i])); + Device->kernels[i] = gcvNULL; + } + } + + { + if (Device->internalLogical != gcvNULL) + { + /* Unmap the internal memory. */ + iounmap(Device->internalLogical); + Device->internalLogical = gcvNULL; + } + + if (Device->internalVidMem != gcvNULL) + { + /* Destroy the internal heap. */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->internalVidMem)); + Device->internalVidMem = gcvNULL; + } + } + + { + if (Device->externalLogical != gcvNULL) + { + /* Unmap the external memory. */ + iounmap(Device->externalLogical); + Device->externalLogical = gcvNULL; + } + + if (Device->externalVidMem != gcvNULL) + { + /* destroy the external heap */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->externalVidMem)); + Device->externalVidMem = gcvNULL; + } + } + + { + if (Device->contiguousBase != gcvNULL) + { + if (Device->contiguousMapped) + { +#if !gcdDYNAMIC_MAP_RESERVED_MEMORY && gcdENABLE_VG + if (Device->contiguousBase) + { + /* Unmap the contiguous memory. */ + iounmap(Device->contiguousBase); + } +#endif + } + else + { + gcmkONERROR(_FreeMemory( + Device, + Device->contiguousBase, + Device->contiguousPhysical + )); + } + + Device->contiguousBase = gcvNULL; + Device->contiguousPhysical = gcvNULL; + } + + if (Device->requestedContiguousBase != 0) + { + release_mem_region(Device->requestedContiguousBase, Device->requestedContiguousSize); + Device->requestedContiguousBase = 0; + Device->requestedContiguousSize = 0; + } + + if (Device->contiguousVidMem != gcvNULL) + { + /* Destroy the contiguous heap. */ + gcmkVERIFY_OK(gckVIDMEM_Destroy(Device->contiguousVidMem)); + Device->contiguousVidMem = gcvNULL; + } + } + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (Device->registerBases[i] != gcvNULL) + { + /* Unmap register memory. */ + iounmap(Device->registerBases[i]); + if (Device->requestedRegisterMemBases[i] != 0) + { + release_mem_region(Device->requestedRegisterMemBases[i], Device->requestedRegisterMemSizes[i]); + } + + Device->registerBases[i] = gcvNULL; + Device->requestedRegisterMemBases[i] = 0; + Device->requestedRegisterMemSizes[i] = 0; + } + } + + /* Destroy the gckOS object. */ + if (Device->os != gcvNULL) + { + gcmkVERIFY_OK(gckOS_Destroy(Device->os)); + Device->os = gcvNULL; + } + + /* Free the device. */ + kfree(Device); + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Setup_ISR +** +** Start the ISR routine. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Setup successfully. +** gcvSTATUS_GENERIC_IO +** Setup failed. +*/ +gceSTATUS +gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ) +{ + gceSTATUS status; + gctINT ret; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->irqLines[gcvCORE_MAJOR] < 0) + { + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Hook up the isr based on the irq line. */ +#ifdef FLAREON + gc500_handle.dev_name = "galcore interrupt service"; + gc500_handle.dev_id = Device; + gc500_handle.handler = isrRoutine; + gc500_handle.intr_gen = GPIO_INTR_LEVEL_TRIGGER; + gc500_handle.intr_trig = GPIO_TRIG_HIGH_LEVEL; + + ret = dove_gpio_request( + DOVE_GPIO0_7, &gc500_handle + ); +#else + ret = request_irq( + Device->irqLines[gcvCORE_MAJOR], isrRoutine, IRQF_DISABLED, + "galcore interrupt service", Device + ); +#endif + + if (ret != 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not register irq line %d (error=%d)\n", + __FUNCTION__, __LINE__, + Device->irqLines[gcvCORE_MAJOR], ret + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Mark ISR as initialized. */ + Device->isrInitializeds[gcvCORE_MAJOR] = gcvTRUE; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckGALDEVICE_Setup_ISR_2D( + IN gckGALDEVICE Device + ) +{ + gceSTATUS status; + gctINT ret; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->irqLines[gcvCORE_2D] < 0) + { + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Hook up the isr based on the irq line. */ +#ifdef FLAREON + gc500_handle.dev_name = "galcore interrupt service"; + gc500_handle.dev_id = Device; + gc500_handle.handler = isrRoutine2D; + gc500_handle.intr_gen = GPIO_INTR_LEVEL_TRIGGER; + gc500_handle.intr_trig = GPIO_TRIG_HIGH_LEVEL; + + ret = dove_gpio_request( + DOVE_GPIO0_7, &gc500_handle + ); +#else + ret = request_irq( + Device->irqLines[gcvCORE_2D], isrRoutine2D, IRQF_DISABLED, + "galcore interrupt service for 2D", Device + ); +#endif + + if (ret != 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not register irq line %d (error=%d)\n", + __FUNCTION__, __LINE__, + Device->irqLines[gcvCORE_2D], ret + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Mark ISR as initialized. */ + Device->isrInitializeds[gcvCORE_2D] = gcvTRUE; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckGALDEVICE_Setup_ISR_VG( + IN gckGALDEVICE Device + ) +{ + gceSTATUS status; + gctINT ret; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->irqLines[gcvCORE_VG] < 0) + { + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Hook up the isr based on the irq line. */ +#ifdef FLAREON + gc500_handle.dev_name = "galcore interrupt service"; + gc500_handle.dev_id = Device; + gc500_handle.handler = isrRoutineVG; + gc500_handle.intr_gen = GPIO_INTR_LEVEL_TRIGGER; + gc500_handle.intr_trig = GPIO_TRIG_HIGH_LEVEL; + + ret = dove_gpio_request( + DOVE_GPIO0_7, &gc500_handle + ); +#else + ret = request_irq( + Device->irqLines[gcvCORE_VG], isrRoutineVG, IRQF_DISABLED, + "galcore interrupt service for 2D", Device + ); +#endif + + if (ret != 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not register irq line %d (error=%d)\n", + __FUNCTION__, __LINE__, + Device->irqLines[gcvCORE_VG], ret + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + /* Mark ISR as initialized. */ + Device->isrInitializeds[gcvCORE_VG] = gcvTRUE; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Release_ISR +** +** Release the irq line. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ) +{ + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* release the irq */ + if (Device->isrInitializeds[gcvCORE_MAJOR]) + { +#ifdef FLAREON + dove_gpio_free(DOVE_GPIO0_7, "galcore interrupt service"); +#else + free_irq(Device->irqLines[gcvCORE_MAJOR], Device); +#endif + + Device->isrInitializeds[gcvCORE_MAJOR] = gcvFALSE; + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckGALDEVICE_Release_ISR_2D( + IN gckGALDEVICE Device + ) +{ + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* release the irq */ + if (Device->isrInitializeds[gcvCORE_2D]) + { +#ifdef FLAREON + dove_gpio_free(DOVE_GPIO0_7, "galcore interrupt service"); +#else + free_irq(Device->irqLines[gcvCORE_2D], Device); +#endif + + Device->isrInitializeds[gcvCORE_2D] = gcvFALSE; + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckGALDEVICE_Release_ISR_VG( + IN gckGALDEVICE Device + ) +{ + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + /* release the irq */ + if (Device->isrInitializeds[gcvCORE_VG]) + { +#ifdef FLAREON + dove_gpio_free(DOVE_GPIO0_7, "galcore interrupt service"); +#else + free_irq(Device->irqLines[gcvCORE_VG], Device); +#endif + + Device->isrInitializeds[gcvCORE_VG] = gcvFALSE; + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start_Threads +** +** Start the daemon threads. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +** gcvSTATUS_GENERIC_IO +** Start failed. +*/ +gceSTATUS +gckGALDEVICE_Start_Threads( + IN gckGALDEVICE Device + ) +{ + gceSTATUS status; + struct task_struct * task; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) + { + /* Start the kernel thread. */ + task = kthread_run(threadRoutine, Device, "galcore daemon thread"); + + if (IS_ERR(task)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not start the kernel thread.\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + Device->threadCtxts[gcvCORE_MAJOR] = task; + Device->threadInitializeds[gcvCORE_MAJOR] = gcvTRUE; + } + + if (Device->kernels[gcvCORE_2D] != gcvNULL) + { + /* Start the kernel thread. */ + task = kthread_run(threadRoutine2D, Device, "galcore daemon thread for 2D"); + + if (IS_ERR(task)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not start the kernel thread.\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + Device->threadCtxts[gcvCORE_2D] = task; + Device->threadInitializeds[gcvCORE_2D] = gcvTRUE; + } + else + { + Device->threadInitializeds[gcvCORE_2D] = gcvFALSE; + } + + if (Device->kernels[gcvCORE_VG] != gcvNULL) + { + /* Start the kernel thread. */ + task = kthread_run(threadRoutineVG, Device, "galcore daemon thread for VG"); + + if (IS_ERR(task)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not start the kernel thread.\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_GENERIC_IO); + } + + Device->threadCtxts[gcvCORE_VG] = task; + Device->threadInitializeds[gcvCORE_VG] = gcvTRUE; + } + else + { + Device->threadInitializeds[gcvCORE_VG] = gcvFALSE; + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop_Threads +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop_Threads( + gckGALDEVICE Device + ) +{ + gctINT i; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + /* Stop the kernel threads. */ + if (Device->threadInitializeds[i]) + { + Device->killThread = gcvTRUE; + up(&Device->semas[i]); + + kthread_stop(Device->threadCtxts[i]); + Device->threadCtxts[i] = gcvNULL; + Device->threadInitializeds[i] = gcvFALSE; + } + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckGALDEVICE_Start +** +** Start the gal device, including the following actions: setup the isr routine +** and start the daemoni thread. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** gcvSTATUS_OK +** Start successfully. +*/ +gceSTATUS +gckGALDEVICE_Start( + IN gckGALDEVICE Device + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Device=0x%x", Device); + + /* Start the kernel thread. */ + gcmkONERROR(gckGALDEVICE_Start_Threads(Device)); + + if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) + { + /* Setup the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Setup_ISR(Device)); + + /* Switch to SUSPEND power state. */ + gcmkONERROR(gckHARDWARE_SetPowerManagementState( + Device->kernels[gcvCORE_MAJOR]->hardware, gcvPOWER_OFF_BROADCAST + )); + } + + if (Device->kernels[gcvCORE_2D] != gcvNULL) + { + /* Setup the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Setup_ISR_2D(Device)); + + /* Switch to SUSPEND power state. */ + gcmkONERROR(gckHARDWARE_SetPowerManagementState( + Device->kernels[gcvCORE_2D]->hardware, gcvPOWER_OFF_BROADCAST + )); + } + + if (Device->kernels[gcvCORE_VG] != gcvNULL) + { + /* Setup the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Setup_ISR_VG(Device)); + } + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckGALDEVICE_Stop +** +** Stop the gal device, including the following actions: stop the daemon +** thread, release the irq. +** +** INPUT: +** +** gckGALDEVICE Device +** Pointer to an gckGALDEVICE object. +** +** OUTPUT: +** +** Nothing. +** +** RETURNS: +** +** Nothing. +*/ +gceSTATUS +gckGALDEVICE_Stop( + gckGALDEVICE Device + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Device=0x%x", Device); + + gcmkVERIFY_ARGUMENT(Device != NULL); + + if (Device->kernels[gcvCORE_MAJOR] != gcvNULL) + { + /* Switch to OFF power state. */ + gcmkONERROR(gckHARDWARE_SetPowerManagementState( + Device->kernels[gcvCORE_MAJOR]->hardware, gcvPOWER_OFF + )); + + /* Remove the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Release_ISR(Device)); + } + + if (Device->kernels[gcvCORE_2D] != gcvNULL) + { + /* Setup the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Release_ISR_2D(Device)); + + /* Switch to OFF power state. */ + gcmkONERROR(gckHARDWARE_SetPowerManagementState( + Device->kernels[gcvCORE_2D]->hardware, gcvPOWER_OFF + )); + } + + if (Device->kernels[gcvCORE_VG] != gcvNULL) + { + /* Setup the ISR routine. */ + gcmkONERROR(gckGALDEVICE_Release_ISR_VG(Device)); + +#if gcdENABLE_VG + /* Switch to OFF power state. */ + gcmkONERROR(gckVGHARDWARE_SetPowerManagementState( + Device->kernels[gcvCORE_VG]->vg->hardware, gcvPOWER_OFF + )); +#endif + } + + /* Stop the kernel thread. */ + gcmkONERROR(gckGALDEVICE_Stop_Threads(Device)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.h b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.h new file mode 100644 index 0000000..a226ba9 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_device.h @@ -0,0 +1,172 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_device_h_ +#define __gc_hal_kernel_device_h_ + +#ifdef ANDROID +#define gcdkREPORT_VIDMEM_LEAK 0 +#else +#define gcdkREPORT_VIDMEM_LEAK 1 +#endif + +/******************************************************************************\ +******************************* gckGALDEVICE Structure ******************************* +\******************************************************************************/ + +typedef struct _gckGALDEVICE +{ + /* Objects. */ + gckOS os; + gckKERNEL kernels[gcdCORE_COUNT]; + + /* Attributes. */ + gctSIZE_T internalSize; + gctPHYS_ADDR internalPhysical; + gctPOINTER internalLogical; + gckVIDMEM internalVidMem; + gctSIZE_T externalSize; + gctPHYS_ADDR externalPhysical; + gctPOINTER externalLogical; + gckVIDMEM externalVidMem; + gckVIDMEM contiguousVidMem; + gctPOINTER contiguousBase; + gctPHYS_ADDR contiguousPhysical; + gctSIZE_T contiguousSize; + gctBOOL contiguousMapped; + gctPOINTER contiguousMappedUser; + gctSIZE_T systemMemorySize; + gctUINT32 systemMemoryBaseAddress; + gctPOINTER registerBases[gcdCORE_COUNT]; + gctSIZE_T registerSizes[gcdCORE_COUNT]; + gctUINT32 baseAddress; + gctUINT32 requestedRegisterMemBases[gcdCORE_COUNT]; + gctSIZE_T requestedRegisterMemSizes[gcdCORE_COUNT]; + gctUINT32 requestedContiguousBase; + gctSIZE_T requestedContiguousSize; + + /* IRQ management. */ + gctINT irqLines[gcdCORE_COUNT]; + gctBOOL isrInitializeds[gcdCORE_COUNT]; + gctBOOL dataReadys[gcdCORE_COUNT]; + + /* Thread management. */ + struct task_struct *threadCtxts[gcdCORE_COUNT]; + struct semaphore semas[gcdCORE_COUNT]; + gctBOOL threadInitializeds[gcdCORE_COUNT]; + gctBOOL killThread; + + /* Signal management. */ + gctINT signal; + + /* Core mapping */ + gceCORE coreMapping[8]; + + /* States before suspend. */ + gceCHIPPOWERSTATE statesStored[gcdCORE_COUNT]; + + /* Clock management. */ + struct clk *clk; + int clk_enabled; + + /* Device pointer for dma_alloc_coherent */ + struct device *dev; +} +* gckGALDEVICE; + +typedef struct _gcsHAL_PRIVATE_DATA +{ + gckGALDEVICE device; + gctPOINTER mappedMemory; + gctPOINTER contiguousLogical; + /* The process opening the device may not be the same as the one that closes it. */ + gctUINT32 pidOpen; +} +gcsHAL_PRIVATE_DATA, * gcsHAL_PRIVATE_DATA_PTR; + +gceSTATUS gckGALDEVICE_Setup_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Setup_ISR_2D( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Setup_ISR_VG( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR_2D( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Release_ISR_VG( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start_Threads( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop_Threads( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Start( + IN gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Stop( + gckGALDEVICE Device + ); + +gceSTATUS gckGALDEVICE_Construct( + IN gctINT IrqLine, + IN gctUINT32 RegisterMemBase, + IN gctSIZE_T RegisterMemSize, + IN gctINT IrqLine2D, + IN gctUINT32 RegisterMemBase2D, + IN gctSIZE_T RegisterMemSize2D, + IN gctINT IrqLineVG, + IN gctUINT32 RegisterMemBaseVG, + IN gctSIZE_T RegisterMemSizeVG, + IN gctUINT32 ContiguousBase, + IN gctSIZE_T ContiguousSize, + IN gctSIZE_T BankSize, + IN gctINT FastClear, + IN gctINT Compression, + IN gctUINT32 PhysBaseAddr, + IN gctUINT32 PhysSize, + IN gctINT Signal, + OUT gckGALDEVICE *Device + ); + +gceSTATUS gckGALDEVICE_Destroy( + IN gckGALDEVICE Device + ); + +#endif /* __gc_hal_kernel_device_h_ */ diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_driver.c b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_driver.c new file mode 100644 index 0000000..55f5a62 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_driver.c @@ -0,0 +1,1087 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include <linux/device.h> +#include <linux/slab.h> + +#include "gc_hal_kernel_linux.h" +#include "gc_hal_driver.h" + +#if USE_PLATFORM_DRIVER +# include <linux/platform_device.h> +#endif + +#ifdef CONFIG_PXA_DVFM +# include <mach/dvfm.h> +# include <mach/pxa3xx_dvfm.h> +#endif + + +/* Zone used for header/footer. */ +#define _GC_OBJ_ZONE gcvZONE_DRIVER + +MODULE_DESCRIPTION("Vivante Graphics Driver"); +MODULE_LICENSE("GPL"); + +static struct class* gpuClass; + +static gckGALDEVICE galDevice; + +static int major = 199; +module_param(major, int, 0644); + +static int irqLine = -1; +module_param(irqLine, int, 0644); + +static long registerMemBase = 0x80000000; +module_param(registerMemBase, long, 0644); + +static ulong registerMemSize = 256 << 10; +module_param(registerMemSize, ulong, 0644); + +static int irqLine2D = -1; +module_param(irqLine2D, int, 0644); + +static long registerMemBase2D = 0x00000000; +module_param(registerMemBase2D, long, 0644); + +static ulong registerMemSize2D = 256 << 10; +module_param(registerMemSize2D, ulong, 0644); + +static int irqLineVG = -1; +module_param(irqLineVG, int, 0644); + +static long registerMemBaseVG = 0x00000000; +module_param(registerMemBaseVG, long, 0644); + +static ulong registerMemSizeVG = 256 << 10; +module_param(registerMemSizeVG, ulong, 0644); + +static long contiguousSize = 4 << 20; +module_param(contiguousSize, long, 0644); + +static ulong contiguousBase = 0; +module_param(contiguousBase, ulong, 0644); + +static long bankSize = 32 << 20; +module_param(bankSize, long, 0644); + +static int fastClear = -1; +module_param(fastClear, int, 0644); + +static int compression = 0; +module_param(compression, int, 0644); + +static int signal = 48; +module_param(signal, int, 0644); + +static ulong baseAddress = 0; +module_param(baseAddress, ulong, 0644); + +static ulong physSize = 0; +module_param(physSize, ulong, 0644); + +static int showArgs = 1; +module_param(showArgs, int, 0644); + +static int drv_open( + struct inode* inode, + struct file* filp + ); + +static int drv_release( + struct inode* inode, + struct file* filp + ); + +static long drv_ioctl( + struct file* filp, + unsigned int ioctlCode, + unsigned long arg + ); + +static int drv_mmap( + struct file* filp, + struct vm_area_struct* vma + ); + +static struct file_operations driver_fops = +{ + .open = drv_open, + .release = drv_release, + .unlocked_ioctl = drv_ioctl, + .mmap = drv_mmap, +}; + +int drv_open( + struct inode* inode, + struct file* filp + ) +{ + gceSTATUS status; + gctBOOL attached = gcvFALSE; + gcsHAL_PRIVATE_DATA_PTR data = gcvNULL; + 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 = kmalloc(sizeof(gcsHAL_PRIVATE_DATA), GFP_KERNEL | __GFP_NOWARN); + + if (data == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): private_data is NULL\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + data->device = galDevice; + data->mappedMemory = gcvNULL; + data->contiguousLogical = gcvNULL; + gcmkONERROR(gckOS_GetProcessID(&data->pidOpen)); + + /* Attached the process. */ + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (galDevice->kernels[i] != gcvNULL) + { + gcmkONERROR(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvTRUE)); + } + } + attached = gcvTRUE; + + if (!galDevice->contiguousMapped) + { + gcmkONERROR(gckOS_MapMemory( + galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + &data->contiguousLogical + )); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (galDevice->kernels[i] != gcvNULL) + { + gcmkVERIFY_OK(gckKERNEL_AddProcessDB( + galDevice->kernels[i], + data->pidOpen, + gcvDB_MAP_MEMORY, + data->contiguousLogical, + galDevice->contiguousPhysical, + galDevice->contiguousSize)); + } + } + } + + filp->private_data = data; + + /* Success. */ + gcmkFOOTER_NO(); + return 0; + +OnError: + if (data != gcvNULL) + { + if (data->contiguousLogical != gcvNULL) + { + gcmkVERIFY_OK(gckOS_UnmapMemory( + galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + data->contiguousLogical + )); + } + + kfree(data); + } + + if (attached) + { + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (galDevice->kernels[i] != gcvNULL) + { + gcmkVERIFY_OK(gckKERNEL_AttachProcess(galDevice->kernels[i], gcvFALSE)); + } + } + } + + gcmkFOOTER(); + return -ENOTTY; +} + +int drv_release( + struct inode* inode, + struct file* filp + ) +{ + gceSTATUS status; + gcsHAL_PRIVATE_DATA_PTR data; + gckGALDEVICE device; + gctINT i; + gctUINT32 processID; + + + 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) + { + gcmkVERIFY_OK(gckOS_GetProcessID(&processID)); + gcmkONERROR(gckOS_UnmapMemoryEx( + galDevice->os, + galDevice->contiguousPhysical, + galDevice->contiguousSize, + data->contiguousLogical, + data->pidOpen + )); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (galDevice->kernels[i] != gcvNULL) + { + gcmkVERIFY_OK( + gckKERNEL_RemoveProcessDB(galDevice->kernels[i], + processID, gcvDB_MAP_MEMORY, + data->contiguousLogical)); + } + } + + data->contiguousLogical = gcvNULL; + } + } + + /* Clean user signals if exit unnormally. */ + gcmkVERIFY_OK(gckOS_GetProcessID(&processID)); + gcmkVERIFY_OK(gckOS_CleanProcessSignal(galDevice->os, (gctHANDLE)processID)); + + /* A process gets detached. */ + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (galDevice->kernels[i] != gcvNULL) + { + gcmkONERROR(gckKERNEL_AttachProcessEx(galDevice->kernels[i], gcvFALSE, data->pidOpen)); + } + } + + kfree(data); + filp->private_data = NULL; + + /* Success. */ + gcmkFOOTER_NO(); + return 0; + +OnError: + gcmkFOOTER(); + return -ENOTTY; +} + +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; + + 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 < gcdCORE_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; + 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); + } + +#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: + gcmkFOOTER(); + return -ENOTTY; +} + +static int drv_mmap( + struct file* filp, + struct vm_area_struct* vma + ) +{ + gceSTATUS status; + gcsHAL_PRIVATE_DATA_PTR data; + gckGALDEVICE device; + + gcmkHEADER_ARG("filp=0x%08X vma=0x%08X", filp, vma); + + 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 !gcdPAGED_MEMORY_CACHEABLE + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND; +#endif + vma->vm_pgoff = 0; + + if (device->contiguousMapped) + { + unsigned long size = vma->vm_end - vma->vm_start; + + int ret = io_remap_pfn_range( + vma, + vma->vm_start, + (gctUINT32) device->contiguousPhysical >> PAGE_SHIFT, + size, + vma->vm_page_prot + ); + + if (ret != 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): io_remap_pfn_range failed %d\n", + __FUNCTION__, __LINE__, + ret + ); + + data->mappedMemory = gcvNULL; + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + data->mappedMemory = (gctPOINTER) vma->vm_start; + } + + /* Success. */ + gcmkFOOTER_NO(); + return 0; + +OnError: + gcmkFOOTER(); + return -ENOTTY; +} + + +#if !USE_PLATFORM_DRIVER +static int __init drv_init(void) +#else +static int drv_init(void) +#endif +{ + int ret; + int result = -EINVAL; + gceSTATUS status; + gckGALDEVICE device = gcvNULL; + struct class* device_class = gcvNULL; + + gcmkHEADER(); + + if (showArgs) + { + printk("galcore options:\n"); + printk(" irqLine = %d\n", irqLine); + printk(" registerMemBase = 0x%08lX\n", registerMemBase); + printk(" registerMemSize = 0x%08lX\n", registerMemSize); + + if (irqLine2D != -1) + { + printk(" irqLine2D = %d\n", irqLine2D); + printk(" registerMemBase2D = 0x%08lX\n", registerMemBase2D); + printk(" registerMemSize2D = 0x%08lX\n", registerMemSize2D); + } + + if (irqLineVG != -1) + { + printk(" irqLineVG = %d\n", irqLineVG); + printk(" registerMemBaseVG = 0x%08lX\n", registerMemBaseVG); + printk(" registerMemSizeVG = 0x%08lX\n", registerMemSizeVG); + } + + printk(" contiguousSize = %ld\n", contiguousSize); + printk(" contiguousBase = 0x%08lX\n", contiguousBase); + printk(" bankSize = 0x%08lX\n", bankSize); + printk(" fastClear = %d\n", fastClear); + printk(" compression = %d\n", compression); + printk(" signal = %d\n", signal); + printk(" baseAddress = 0x%08lX\n", baseAddress); + printk(" physSize = 0x%08lX\n", physSize); + } + + /* Create the GAL device. */ + gcmkONERROR(gckGALDEVICE_Construct( + irqLine, + registerMemBase, registerMemSize, + irqLine2D, + registerMemBase2D, registerMemSize2D, + irqLineVG, + registerMemBaseVG, registerMemSizeVG, + contiguousBase, contiguousSize, + bankSize, fastClear, compression, baseAddress, physSize, signal, + &device + )); + + /* Start the GAL device. */ + gcmkONERROR(gckGALDEVICE_Start(device)); + + if ((physSize != 0) + && (device->kernels[gcvCORE_MAJOR] != gcvNULL) + && (device->kernels[gcvCORE_MAJOR]->hardware->mmuVersion != 0)) + { + status = gckMMU_Enable(device->kernels[gcvCORE_MAJOR]->mmu, baseAddress, physSize); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Enable new MMU: status=%d\n", status); + + if ((device->kernels[gcvCORE_2D] != gcvNULL) + && (device->kernels[gcvCORE_2D]->hardware->mmuVersion != 0)) + { + status = gckMMU_Enable(device->kernels[gcvCORE_2D]->mmu, baseAddress, physSize); + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_DRIVER, + "Enable new MMU for 2D: status=%d\n", status); + } + + /* Reset the base address */ + device->baseAddress = 0; + } + + /* Register the character device. */ + ret = register_chrdev(major, DRV_NAME, &driver_fops); + + if (ret < 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Could not allocate major number for mmap.\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + if (major == 0) + { + major = ret; + } + + /* Create the device class. */ + device_class = class_create(THIS_MODULE, "graphics_class"); + + if (IS_ERR(device_class)) + { + gcmkTRACE_ZONE( + gcvLEVEL_ERROR, gcvZONE_DRIVER, + "%s(%d): Failed to create the class.\n", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + device_create(device_class, NULL, MKDEV(major, 0), NULL, "galcore"); +#else + device_create(device_class, NULL, MKDEV(major, 0), "galcore"); +#endif + + galDevice = device; + gpuClass = device_class; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_DRIVER, + "%s(%d): irqLine=%d, contiguousSize=%lu, memBase=0x%lX\n", + __FUNCTION__, __LINE__, + irqLine, contiguousSize, registerMemBase + ); + + /* Success. */ + gcmkFOOTER_NO(); + return 0; + +OnError: + /* Roll back. */ + if (device_class != gcvNULL) + { + device_destroy(device_class, MKDEV(major, 0)); + class_destroy(device_class); + } + + if (device != gcvNULL) + { + gcmkVERIFY_OK(gckGALDEVICE_Stop(device)); + gcmkVERIFY_OK(gckGALDEVICE_Destroy(device)); + } + + gcmkFOOTER(); + return result; +} + +#if !USE_PLATFORM_DRIVER +static void __exit drv_exit(void) +#else +static void drv_exit(void) +#endif +{ + struct clk *clk = galDevice->clk; + + gcmkHEADER(); + + gcmkASSERT(gpuClass != gcvNULL); + device_destroy(gpuClass, MKDEV(major, 0)); + class_destroy(gpuClass); + + unregister_chrdev(major, DRV_NAME); + + gcmkVERIFY_OK(gckGALDEVICE_Stop(galDevice)); + gcmkVERIFY_OK(gckGALDEVICE_Destroy(galDevice)); + + clk_disable(clk); + clk_put(clk); + + gcmkFOOTER_NO(); +} + +#if !USE_PLATFORM_DRIVER + module_init(drv_init); + module_exit(drv_exit); +#else + +#ifdef CONFIG_DOVE_GPU +# define DEVICE_NAME "dove_gpu" +#else +# define DEVICE_NAME "galcore" +#endif + +static int __devinit gpu_probe(struct platform_device *pdev) +{ + int ret = -ENODEV; + struct resource* res; + struct clk *clk; + + gcmkHEADER(); + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "gpu_irq"); + + if (!res) + { + printk(KERN_ERR "%s: No irq line supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + + irqLine = res->start; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpu_base"); + + if (!res) + { + printk(KERN_ERR "%s: No register base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + + registerMemBase = res->start; + registerMemSize = res->end - res->start + 1; + + res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "gpu_mem"); + + if (!res) + { + printk(KERN_ERR "%s: No memory base supplied.\n",__FUNCTION__); + goto gpu_probe_fail; + } + + contiguousBase = res->start; + contiguousSize = res->end - res->start + 1; + + dev_info(&pdev->dev, "driver v4.6.6, initializing\n"); + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "cannot get clock\n"); + ret = PTR_ERR(clk); + goto gpu_probe_fail; + } + clk_enable(clk); + + ret = drv_init(); + galDevice->dev = &pdev->dev; + + if (!ret) + { + platform_set_drvdata(pdev, galDevice); + galDevice->clk = clk; + galDevice->clk_enabled = 0; + + dev_info(&pdev->dev, "GPU initialized, clocked at %luMHz\n", + clk_get_rate(clk) / 1000000); + + clk_disable(clk); + + gcmkFOOTER_NO(); + return ret; + } + + clk_disable(clk); + clk_put(clk); + +gpu_probe_fail: + gcmkFOOTER_ARG(KERN_INFO "Failed to register gpu driver: %d\n", ret); + return ret; +} + +static int __devinit gpu_remove(struct platform_device *pdev) +{ + gcmkHEADER(); + drv_exit(); + gcmkFOOTER_NO(); + return 0; +} + +static int __devinit gpu_suspend(struct platform_device *dev, pm_message_t state) +{ + gceSTATUS status; + gckGALDEVICE device; + gctINT i; + + device = platform_get_drvdata(dev); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (device->kernels[i] != gcvNULL) + { + /* Store states. */ +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + status = gckVGHARDWARE_QueryPowerManagementState(device->kernels[i]->vg->hardware, &device->statesStored[i]); + } + else +#endif + { + status = gckHARDWARE_QueryPowerManagementState(device->kernels[i]->hardware, &device->statesStored[i]); + } + + if (gcmIS_ERROR(status)) + { + return -1; + } + +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_OFF); + } + else +#endif + { + status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_OFF); + } + + if (gcmIS_ERROR(status)) + { + return -1; + } + + } + } + + return 0; +} + +static int __devinit gpu_resume(struct platform_device *dev) +{ + gceSTATUS status; + gckGALDEVICE device; + gctINT i; + gceCHIPPOWERSTATE statesStored; + + device = platform_get_drvdata(dev); + + for (i = 0; i < gcdCORE_COUNT; i++) + { + if (device->kernels[i] != gcvNULL) + { +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, gcvPOWER_ON); + } + else +#endif + { + status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, gcvPOWER_ON); + } + + if (gcmIS_ERROR(status)) + { + return -1; + } + + /* Convert global state to crossponding internal state. */ + switch(device->statesStored[i]) + { + case gcvPOWER_OFF: + statesStored = gcvPOWER_OFF_BROADCAST; + break; + case gcvPOWER_IDLE: + statesStored = gcvPOWER_IDLE_BROADCAST; + break; + case gcvPOWER_SUSPEND: + statesStored = gcvPOWER_SUSPEND_BROADCAST; + break; + case gcvPOWER_ON: + statesStored = gcvPOWER_ON_AUTO; + break; + default: + statesStored = device->statesStored[i]; + break; + } + + /* Restore states. */ +#if gcdENABLE_VG + if (i == gcvCORE_VG) + { + status = gckVGHARDWARE_SetPowerManagementState(device->kernels[i]->vg->hardware, statesStored); + } + else +#endif + { + status = gckHARDWARE_SetPowerManagementState(device->kernels[i]->hardware, statesStored); + } + + if (gcmIS_ERROR(status)) + { + return -1; + } + } + } + + return 0; +} + +static struct platform_driver gpu_driver = { + .probe = gpu_probe, + .remove = gpu_remove, + + .suspend = gpu_suspend, + .resume = gpu_resume, + + .driver = { + .name = DEVICE_NAME, + } +}; + +static int __init gpu_init(void) +{ + int ret = 0; + + ret = platform_driver_register(&gpu_driver); + return ret; +} + +static void __exit gpu_exit(void) +{ + platform_driver_unregister(&gpu_driver); +} + +module_init(gpu_init); +module_exit(gpu_exit); + +#endif diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.c b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.c new file mode 100644 index 0000000..cba2040 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.c @@ -0,0 +1,470 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#define _GC_OBJ_ZONE gcvZONE_KERNEL + +/******************************************************************************\ +******************************* gckKERNEL API Code ****************************** +\******************************************************************************/ + +/******************************************************************************* +** +** gckKERNEL_QueryVideoMemory +** +** Query the amount of video memory. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** OUTPUT: +** +** gcsHAL_INTERFACE * Interface +** Pointer to an gcsHAL_INTERFACE structure that will be filled in with +** the memory information. +*/ +gceSTATUS +gckKERNEL_QueryVideoMemory( + IN gckKERNEL Kernel, + OUT gcsHAL_INTERFACE * Interface + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Interface != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Get internal memory size and physical address. */ + Interface->u.QueryVideoMemory.internalSize = device->internalSize; + Interface->u.QueryVideoMemory.internalPhysical = device->internalPhysical; + + /* Get external memory size and physical address. */ + Interface->u.QueryVideoMemory.externalSize = device->externalSize; + Interface->u.QueryVideoMemory.externalPhysical = device->externalPhysical; + + /* Get contiguous memory size and physical address. */ + Interface->u.QueryVideoMemory.contiguousSize = device->contiguousSize; + Interface->u.QueryVideoMemory.contiguousPhysical = device->contiguousPhysical; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_GetVideoMemoryPool +** +** Get the gckVIDMEM object belonging to the specified pool. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gcePOOL Pool +** Pool to query gckVIDMEM object for. +** +** OUTPUT: +** +** gckVIDMEM * VideoMemory +** Pointer to a variable that will hold the pointer to the gckVIDMEM +** object belonging to the requested pool. +*/ +gceSTATUS +gckKERNEL_GetVideoMemoryPool( + IN gckKERNEL Kernel, + IN gcePOOL Pool, + OUT gckVIDMEM * VideoMemory + ) +{ + gckGALDEVICE device; + gckVIDMEM videoMemory; + + gcmkHEADER_ARG("Kernel=%p Pool=%d", Kernel, Pool); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(VideoMemory != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Dispatch on pool. */ + switch (Pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + videoMemory = device->internalVidMem; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + videoMemory = device->externalVidMem; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + videoMemory = device->contiguousVidMem; + break; + + default: + /* Unknown pool. */ + videoMemory = NULL; + } + + /* Return pointer to the gckVIDMEM object. */ + *VideoMemory = videoMemory; + + /* Return status. */ + gcmkFOOTER_ARG("*VideoMemory=%p", *VideoMemory); + return (videoMemory == NULL) ? gcvSTATUS_OUT_OF_MEMORY : gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckKERNEL_MapMemory +** +** Map video memory into the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the base address of the mapped +** memory region. +*/ +gceSTATUS +gckKERNEL_MapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + return gckOS_MapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_UnmapMemory +** +** Unmap video memory from the current process space. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctPHYS_ADDR Physical +** Physical address of video memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** gctPOINTER Logical +** Base address of the mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_UnmapMemory( + IN gckKERNEL Kernel, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + return gckOS_UnmapMemory(Kernel->os, Physical, Bytes, Logical); +} + +/******************************************************************************* +** +** gckKERNEL_MapVideoMemory +** +** Get the logical address for a hardware specific memory address for the +** current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL InUserSpace +** gcvTRUE to map the memory into the user space. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** specified memory address. +*/ +gceSTATUS +gckKERNEL_MapVideoMemoryEx( + IN gckKERNEL Kernel, + IN gceCORE Core, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, + OUT gctPOINTER * Logical + ) +{ + gckGALDEVICE device; + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gcePOOL pool; + gctUINT32 offset, base; + gceSTATUS status; + gctPOINTER logical; + + gcmkHEADER_ARG("Kernel=%p InUserSpace=%d Address=%08x", + Kernel, InUserSpace, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Logical != NULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + /* Split the memory address into a pool type and offset. */ + gcmkONERROR( + gckVGHARDWARE_SplitMemory(Kernel->vg->hardware, Address, &pool, &offset)); + } + else +#endif + { + /* Split the memory address into a pool type and offset. */ + gcmkONERROR( + gckHARDWARE_SplitMemory(Kernel->hardware, Address, &pool, &offset)); + } + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + if (device->contiguousMapped) + { + logical = device->contiguousBase; + } + else + { + gctINT processID; + gckOS_GetProcessID(&processID); + + mdl = (PLINUX_MDL) device->contiguousPhysical; + + mdlMap = FindMdlMap(mdl, processID); + gcmkASSERT(mdlMap); + + logical = (gctPOINTER) mdlMap->vmaAddr; + } +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + gcmkVERIFY_OK( + gckVGHARDWARE_SplitMemory(Kernel->vg->hardware, + device->contiguousVidMem->baseAddress, + &pool, + &base)); + } + else +#endif + { + gcmkVERIFY_OK( + gckHARDWARE_SplitMemory(Kernel->hardware, + device->contiguousVidMem->baseAddress, + &pool, + &base)); + } + offset -= base; + break; + + default: + /* Invalid memory pool. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Build logical address of specified address. */ + *Logical = (gctPOINTER) ((gctUINT8_PTR) logical + offset); + + /* Success. */ + gcmkFOOTER_ARG("*Logical=%p", *Logical); + return gcvSTATUS_OK; + +OnError: + /* Retunn the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckKERNEL_MapVideoMemory +** +** Get the logical address for a hardware specific memory address for the +** current process. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gctBOOL InUserSpace +** gcvTRUE to map the memory into the user space. +** +** gctUINT32 Address +** Hardware specific memory address. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** specified memory address. +*/ +gceSTATUS +gckKERNEL_MapVideoMemory( + IN gckKERNEL Kernel, + IN gctBOOL InUserSpace, + IN gctUINT32 Address, + OUT gctPOINTER * Logical + ) +{ + return gckKERNEL_MapVideoMemoryEx(Kernel, gcvCORE_MAJOR, InUserSpace, Address, Logical); +} +/******************************************************************************* +** +** gckKERNEL_Notify +** +** This function iscalled by clients to notify the gckKERNRL object of an event. +** +** INPUT: +** +** gckKERNEL Kernel +** Pointer to an gckKERNEL object. +** +** gceNOTIFY Notification +** Notification event. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckKERNEL_Notify( + IN gckKERNEL Kernel, + IN gceNOTIFY Notification, + IN gctBOOL Data + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Kernel=%p Notification=%d Data=%d", + Kernel, Notification, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + + /* Dispatch on notifcation. */ + switch (Notification) + { + case gcvNOTIFY_INTERRUPT: + /* Process the interrupt. */ +#if COMMAND_PROCESSOR_VERSION > 1 + status = gckINTERRUPT_Notify(Kernel->interrupt, Data); +#else + status = gckHARDWARE_Interrupt(Kernel->hardware, Data); +#endif + break; + + default: + status = gcvSTATUS_OK; + break; + } + + /* Success. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckKERNEL_QuerySettings( + IN gckKERNEL Kernel, + OUT gcsKERNEL_SETTINGS * Settings + ) +{ + gckGALDEVICE device; + + gcmkHEADER_ARG("Kernel=%p", Kernel); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Kernel, gcvOBJ_KERNEL); + gcmkVERIFY_ARGUMENT(Settings != gcvNULL); + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Kernel->context; + + /* Fill in signal. */ + Settings->signal = device->signal; + + /* Success. */ + gcmkFOOTER_ARG("Settings->signal=%d", Settings->signal); + return gcvSTATUS_OK; +} diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.h b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.h new file mode 100644 index 0000000..fba7e0f --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_linux.h @@ -0,0 +1,86 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_linux_h_ +#define __gc_hal_kernel_linux_h_ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/signal.h> +#ifdef FLAREON +# include <asm/arch-realview/dove_gpio_irq.h> +#endif +#include <linux/interrupt.h> +#include <linux/vmalloc.h> +#include <linux/dma-mapping.h> +#include <linux/kthread.h> + +#ifdef MODVERSIONS +# include <linux/modversions.h> +#endif +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <linux/clk.h> + +#define NTSTRSAFE_NO_CCH_FUNCTIONS +#include "gc_hal.h" +#include "gc_hal_driver.h" +#include "gc_hal_kernel.h" +#include "gc_hal_kernel_device.h" +#include "gc_hal_kernel_os.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) +#define FIND_TASK_BY_PID(x) pid_task(find_vpid(x), PIDTYPE_PID) +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#define FIND_TASK_BY_PID(x) find_task_by_vpid(x) +#else +#define FIND_TASK_BY_PID(x) find_task_by_pid(x) +#endif + +#define _WIDE(string) L##string +#define WIDE(string) _WIDE(string) + +#define countof(a) (sizeof(a) / sizeof(a[0])) + +#define DRV_NAME "galcore" + +#define GetPageCount(size, offset) ((((size) + ((offset) & ~PAGE_CACHE_MASK)) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) + +static inline gctINT +GetOrder( + IN gctINT numPages + ) +{ + gctINT order = 0; + + while ((1 << order) < numPages) order++; + + return order; +} + +#endif /* __gc_hal_kernel_linux_h_ */ diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_math.c b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_math.c new file mode 100644 index 0000000..a4cb717 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_math.c @@ -0,0 +1,34 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +gctINT +gckMATH_ModuloInt( + IN gctINT X, + IN gctINT Y + ) +{ + if(Y ==0) {return 0;} + else {return X % Y;} +} diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.c b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.c new file mode 100644 index 0000000..d7b30d7 --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.c @@ -0,0 +1,8593 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#include "gc_hal_kernel_linux.h" + +#include <linux/pagemap.h> +#include <linux/seq_file.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/sched.h> +#include <asm/atomic.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) +#include <linux/math64.h> +#endif + +#define _GC_OBJ_ZONE gcvZONE_OS + +/******************************************************************************* +***** Version Signature *******************************************************/ + +#ifdef ANDROID +const char * _PLATFORM = "\n\0$PLATFORM$Android$\n"; +#else +const char * _PLATFORM = "\n\0$PLATFORM$Linux$\n"; +#endif + +#define USER_SIGNAL_TABLE_LEN_INIT 64 + +#define MEMORY_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryLock, \ + gcvINFINITE)) + +#define MEMORY_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryLock)) + +#define MEMORY_MAP_LOCK(os) \ + gcmkVERIFY_OK(gckOS_AcquireMutex( \ + (os), \ + (os)->memoryMapLock, \ + gcvINFINITE)) + +#define MEMORY_MAP_UNLOCK(os) \ + gcmkVERIFY_OK(gckOS_ReleaseMutex((os), (os)->memoryMapLock)) + +/* Protection bit when mapping memroy to user sapce */ +#define gcmkPAGED_MEMROY_PROT(x) pgprot_writecombine(x) + +#if gcdNONPAGED_MEMORY_BUFFERABLE +#define gcmkIOREMAP ioremap_wc +#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_writecombine(x) +#elif !gcdNONPAGED_MEMORY_CACHEABLE +#define gcmkIOREMAP ioremap_nocache +#define gcmkNONPAGED_MEMROY_PROT(x) pgprot_noncached(x) +#endif + +#define gcdINFINITE_TIMEOUT (60 * 1000) +#define gcdDETECT_TIMEOUT 0 +#define gcdDETECT_DMA_ADDRESS 1 +#define gcdDETECT_DMA_STATE 1 + +#define gcdUSE_NON_PAGED_MEMORY_CACHE 10 + +/******************************************************************************\ +********************************** Structures ********************************** +\******************************************************************************/ +#if gcdUSE_NON_PAGED_MEMORY_CACHE +typedef struct _gcsNonPagedMemoryCache +{ +#ifndef NO_DMA_COHERENT + gctINT size; + gctSTRING addr; + dma_addr_t dmaHandle; +#else + long order; + struct page * page; +#endif + + struct _gcsNonPagedMemoryCache * prev; + struct _gcsNonPagedMemoryCache * next; +} +gcsNonPagedMemoryCache; +#endif /* gcdUSE_NON_PAGED_MEMORY_CACHE */ + +typedef struct _gcsUSER_MAPPING * gcsUSER_MAPPING_PTR; +typedef struct _gcsUSER_MAPPING +{ + /* Pointer to next mapping structure. */ + gcsUSER_MAPPING_PTR next; + + /* Physical address of this mapping. */ + gctUINT32 physical; + + /* Logical address of this mapping. */ + gctPOINTER logical; + + /* Number of bytes of this mapping. */ + gctSIZE_T bytes; + + /* Starting address of this mapping. */ + gctINT8_PTR start; + + /* Ending address of this mapping. */ + gctINT8_PTR end; +} +gcsUSER_MAPPING; + +struct _gckOS +{ + /* Object. */ + gcsOBJECT object; + + /* Heap. */ + gckHEAP heap; + + /* Pointer to device */ + gckGALDEVICE device; + + /* Memory management */ + gctPOINTER memoryLock; + gctPOINTER memoryMapLock; + + struct _LINUX_MDL *mdlHead; + struct _LINUX_MDL *mdlTail; + + /* Kernel process ID. */ + gctUINT32 kernelProcessID; + + /* Signal management. */ + struct _signal + { + /* Unused signal ID number. */ + gctINT unused; + + /* The pointer to the table. */ + gctPOINTER * table; + + /* Signal table length. */ + gctINT tableLen; + + /* The current unused signal ID. */ + gctINT currentID; + + /* Lock. */ + gctPOINTER lock; + } + signal; + + gcsUSER_MAPPING_PTR userMap; + gctPOINTER debugLock; + +#if gcdUSE_NON_PAGED_MEMORY_CACHE + gctUINT cacheSize; + gcsNonPagedMemoryCache * cacheHead; + gcsNonPagedMemoryCache * cacheTail; +#endif + + /* workqueue for os timer. */ + struct workqueue_struct * workqueue; +}; + +typedef struct _gcsSIGNAL * gcsSIGNAL_PTR; +typedef struct _gcsSIGNAL +{ + /* Kernel sync primitive. */ + struct completion obj; + + /* Manual reset flag. */ + gctBOOL manualReset; + + /* The reference counter. */ + atomic_t ref; + + /* The owner of the signal. */ + gctHANDLE process; +} +gcsSIGNAL; + +typedef struct _gcsPageInfo * gcsPageInfo_PTR; +typedef struct _gcsPageInfo +{ + struct page **pages; + gctUINT32_PTR pageTable; +} +gcsPageInfo; + +typedef struct _gcsiDEBUG_REGISTERS * gcsiDEBUG_REGISTERS_PTR; +typedef struct _gcsiDEBUG_REGISTERS +{ + gctSTRING module; + gctUINT index; + gctUINT shift; + gctUINT data; + gctUINT count; + gctUINT32 signature; +} +gcsiDEBUG_REGISTERS; + +typedef struct _gcsOSTIMER * gcsOSTIMER_PTR; +typedef struct _gcsOSTIMER +{ + struct delayed_work work; + gctTIMERFUNCTION function; + gctPOINTER data; +} gcsOSTIMER; + +/******************************************************************************\ +******************************* Private Functions ****************************** +\******************************************************************************/ + +static gceSTATUS +_VerifyDMA( + IN gckOS Os, + IN gceCORE Core, + gctUINT32_PTR Address1, + gctUINT32_PTR Address2, + gctUINT32_PTR State1, + gctUINT32_PTR State2 + ) +{ + gceSTATUS status; + gctUINT32 i; + + gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State1)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address1)); + + for (i = 0; i < 500; i += 1) + { + gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x660, State2)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, Core, 0x664, Address2)); + + if (*Address1 != *Address2) + { + break; + } + +#if gcdDETECT_DMA_STATE + if (*State1 != *State2) + { + break; + } +#endif + } + +OnError: + return status; +} + +static gceSTATUS +_DumpDebugRegisters( + IN gckOS Os, + IN gcsiDEBUG_REGISTERS_PTR Descriptor + ) +{ + gceSTATUS status; + gctUINT32 select; + gctUINT32 data; + gctUINT i; + + gcmkHEADER_ARG("Os=0x%X Descriptor=0x%X", Os, Descriptor); + + gcmkPRINT_N(4, " %s debug registers:\n", Descriptor->module); + + select = 0xF << Descriptor->shift; + + for (i = 0; i < 500; i += 1) + { + gcmkONERROR(gckOS_WriteRegister(Os, Descriptor->index, select)); +#if !gcdENABLE_RECOVERY + gcmkONERROR(gckOS_Delay(Os, 1000)); +#endif + gcmkONERROR(gckOS_ReadRegister(Os, Descriptor->data, &data)); + + if (data == Descriptor->signature) + { + break; + } + } + + if (i == 500) + { + gcmkPRINT_N(4, " failed to obtain the signature (read 0x%08X).\n", data); + } + else + { + gcmkPRINT_N(8, " signature = 0x%08X (%d read attempt(s))\n", data, i + 1); + } + + for (i = 0; i < Descriptor->count; i += 1) + { + select = i << Descriptor->shift; + + gcmkONERROR(gckOS_WriteRegister(Os, Descriptor->index, select)); +#if !gcdENABLE_RECOVERY + gcmkONERROR(gckOS_Delay(Os, 1000)); +#endif + gcmkONERROR(gckOS_ReadRegister(Os, Descriptor->data, &data)); + + gcmkPRINT_N(12, " [0x%02X] 0x%08X\n", i, data); + } + +OnError: + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +static gceSTATUS +_DumpGPUState( + IN gckOS Os, + IN gceCORE Core + ) +{ + static gctCONST_STRING _cmdState[] = + { + "PAR_IDLE_ST", "PAR_DEC_ST", "PAR_ADR0_ST", "PAR_LOAD0_ST", + "PAR_ADR1_ST", "PAR_LOAD1_ST", "PAR_3DADR_ST", "PAR_3DCMD_ST", + "PAR_3DCNTL_ST", "PAR_3DIDXCNTL_ST", "PAR_INITREQDMA_ST", + "PAR_DRAWIDX_ST", "PAR_DRAW_ST", "PAR_2DRECT0_ST", "PAR_2DRECT1_ST", + "PAR_2DDATA0_ST", "PAR_2DDATA1_ST", "PAR_WAITFIFO_ST", "PAR_WAIT_ST", + "PAR_LINK_ST", "PAR_END_ST", "PAR_STALL_ST" + }; + + static gctCONST_STRING _cmdDmaState[] = + { + "CMD_IDLE_ST", "CMD_START_ST", "CMD_REQ_ST", "CMD_END_ST" + }; + + static gctCONST_STRING _cmdFetState[] = + { + "FET_IDLE_ST", "FET_RAMVALID_ST", "FET_VALID_ST" + }; + + static gctCONST_STRING _reqDmaState[] = + { + "REQ_IDLE_ST", "REQ_WAITIDX_ST", "REQ_CAL_ST" + }; + + static gctCONST_STRING _calState[] = + { + "CAL_IDLE_ST", "CAL_LDADR_ST", "CAL_IDXCALC_ST" + }; + + static gctCONST_STRING _veReqState[] = + { + "VER_IDLE_ST", "VER_CKCACHE_ST", "VER_MISS_ST" + }; + + static gcsiDEBUG_REGISTERS _dbgRegs[] = + { + { "RA", 0x474, 16, 0x448, 16, 0x12344321 }, + { "TX", 0x474, 24, 0x44C, 16, 0x12211221 }, + { "FE", 0x470, 0, 0x450, 16, 0xBABEF00D }, + { "PE", 0x470, 16, 0x454, 16, 0xBABEF00D }, + { "DE", 0x470, 8, 0x458, 16, 0xBABEF00D }, + { "SH", 0x470, 24, 0x45C, 16, 0xDEADBEEF }, + { "PA", 0x474, 0, 0x460, 16, 0x0000AAAA }, + { "SE", 0x474, 8, 0x464, 16, 0x5E5E5E5E }, + { "MC", 0x478, 0, 0x468, 16, 0x12345678 }, + { "HI", 0x478, 8, 0x46C, 16, 0xAAAAAAAA } + }; + + static gctUINT32 _otherRegs[] = + { + 0x040, 0x044, 0x04C, 0x050, 0x054, 0x058, 0x05C, 0x060, + 0x43c, 0x440, 0x444, 0x414, + }; + + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + gckGALDEVICE device; + gckKERNEL kernel; + gctUINT32 idle, axi; + gctUINT32 dmaAddress1, dmaAddress2; + gctUINT32 dmaState1, dmaState2; + gctUINT32 dmaLow, dmaHigh; + gctUINT32 cmdState, cmdDmaState, cmdFetState; + gctUINT32 dmaReqState, calState, veReqState; + gctUINT i; + + gcmkHEADER_ARG("Os=0x%X, Core=%d", Os, Core); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->debugLock, gcvINFINITE)); + acquired = gcvTRUE; + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Os->device; + + /* TODO: Kernel shortcut. */ + kernel = device->kernels[Core]; + gcmkPRINT_N(4, "Core = 0x%d\n",Core); + + if (kernel == gcvNULL) + { + gcmkFOOTER(); + return gcvSTATUS_OK; + } + + /* Reset register values. */ + idle = axi = + dmaState1 = dmaState2 = + dmaAddress1 = dmaAddress2 = + dmaLow = dmaHigh = 0; + + /* Verify whether DMA is running. */ + gcmkONERROR(_VerifyDMA( + Os, kernel->core, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2 + )); + + cmdState = dmaState2 & 0x1F; + cmdDmaState = (dmaState2 >> 8) & 0x03; + cmdFetState = (dmaState2 >> 10) & 0x03; + dmaReqState = (dmaState2 >> 12) & 0x03; + calState = (dmaState2 >> 14) & 0x03; + veReqState = (dmaState2 >> 16) & 0x03; + + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x004, &idle)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x00C, &axi)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x668, &dmaLow)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x66C, &dmaHigh)); + + gcmkPRINT_N(0, "**************************\n"); + gcmkPRINT_N(0, "*** GPU STATE DUMP ***\n"); + gcmkPRINT_N(0, "**************************\n"); + + gcmkPRINT_N(4, " axi = 0x%08X\n", axi); + + gcmkPRINT_N(4, " idle = 0x%08X\n", idle); + if ((idle & 0x00000001) == 0) gcmkPRINT_N(0, " FE not idle\n"); + if ((idle & 0x00000002) == 0) gcmkPRINT_N(0, " DE not idle\n"); + if ((idle & 0x00000004) == 0) gcmkPRINT_N(0, " PE not idle\n"); + if ((idle & 0x00000008) == 0) gcmkPRINT_N(0, " SH not idle\n"); + if ((idle & 0x00000010) == 0) gcmkPRINT_N(0, " PA not idle\n"); + if ((idle & 0x00000020) == 0) gcmkPRINT_N(0, " SE not idle\n"); + if ((idle & 0x00000040) == 0) gcmkPRINT_N(0, " RA not idle\n"); + if ((idle & 0x00000080) == 0) gcmkPRINT_N(0, " TX not idle\n"); + if ((idle & 0x00000100) == 0) gcmkPRINT_N(0, " VG not idle\n"); + if ((idle & 0x00000200) == 0) gcmkPRINT_N(0, " IM not idle\n"); + if ((idle & 0x00000400) == 0) gcmkPRINT_N(0, " FP not idle\n"); + if ((idle & 0x00000800) == 0) gcmkPRINT_N(0, " TS not idle\n"); + if ((idle & 0x80000000) != 0) gcmkPRINT_N(0, " AXI low power mode\n"); + + if ( + (dmaAddress1 == dmaAddress2) + +#if gcdDETECT_DMA_STATE + && (dmaState1 == dmaState2) +#endif + ) + { + gcmkPRINT_N(0, " DMA appears to be stuck at this address:\n"); + gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1); + } + else + { + if (dmaAddress1 == dmaAddress2) + { + gcmkPRINT_N(0, " DMA address is constant, but state is changing:\n"); + gcmkPRINT_N(4, " 0x%08X\n", dmaState1); + gcmkPRINT_N(4, " 0x%08X\n", dmaState2); + } + else + { + gcmkPRINT_N(0, " DMA is running; known addresses are:\n"); + gcmkPRINT_N(4, " 0x%08X\n", dmaAddress1); + gcmkPRINT_N(4, " 0x%08X\n", dmaAddress2); + } + } + + gcmkPRINT_N(4, " dmaLow = 0x%08X\n", dmaLow); + gcmkPRINT_N(4, " dmaHigh = 0x%08X\n", dmaHigh); + gcmkPRINT_N(4, " dmaState = 0x%08X\n", dmaState2); + gcmkPRINT_N(8, " command state = %d (%s)\n", cmdState, _cmdState [cmdState]); + gcmkPRINT_N(8, " command DMA state = %d (%s)\n", cmdDmaState, _cmdDmaState[cmdDmaState]); + gcmkPRINT_N(8, " command fetch state = %d (%s)\n", cmdFetState, _cmdFetState[cmdFetState]); + gcmkPRINT_N(8, " DMA request state = %d (%s)\n", dmaReqState, _reqDmaState[dmaReqState]); + gcmkPRINT_N(8, " cal state = %d (%s)\n", calState, _calState [calState]); + gcmkPRINT_N(8, " VE request state = %d (%s)\n", veReqState, _veReqState [veReqState]); + + for (i = 0; i < gcmCOUNTOF(_dbgRegs); i += 1) + { + gcmkONERROR(_DumpDebugRegisters(Os, &_dbgRegs[i])); + } + + if (kernel->hardware->identity.chipFeatures & (1 << 4)) + { + gctUINT32 read0, read1, write; + + read0 = read1 = write = 0; + + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x43C, &read0)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x440, &read1)); + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, 0x444, &write)); + + gcmkPRINT_N(4, " read0 = 0x%08X\n", read0); + gcmkPRINT_N(4, " read1 = 0x%08X\n", read1); + gcmkPRINT_N(4, " write = 0x%08X\n", write); + } + + gcmkPRINT_N(0, " Other Registers:\n"); + for (i = 0; i < gcmCOUNTOF(_otherRegs); i += 1) + { + gctUINT32 read; + gcmkONERROR(gckOS_ReadRegisterEx(Os, kernel->core, _otherRegs[i], &read)); + gcmkPRINT_N(12, " [0x%04X] 0x%08X\n", _otherRegs[i], read); + } + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->debugLock)); + } + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +static gctINT +_GetProcessID( + void + ) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + return task_tgid_vnr(current); +#else + return current->tgid; +#endif +} + +static gctINT +_GetThreadID( + void + ) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + return task_pid_vnr(current); +#else + return current->pid; +#endif +} + +static PLINUX_MDL +_CreateMdl( + IN gctINT ProcessID + ) +{ + PLINUX_MDL mdl; + + gcmkHEADER_ARG("ProcessID=%d", ProcessID); + + mdl = (PLINUX_MDL)kmalloc(sizeof(struct _LINUX_MDL), GFP_KERNEL | __GFP_NOWARN); + if (mdl == gcvNULL) + { + gcmkFOOTER_NO(); + return gcvNULL; + } + + mdl->pid = ProcessID; + mdl->maps = gcvNULL; + mdl->prev = gcvNULL; + mdl->next = gcvNULL; + + gcmkFOOTER_ARG("0x%X", mdl); + return mdl; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ); + +static gceSTATUS +_DestroyMdl( + IN PLINUX_MDL Mdl + ) +{ + PLINUX_MDL_MAP mdlMap, next; + + gcmkHEADER_ARG("Mdl=0x%X", Mdl); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Mdl != gcvNULL); + + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + next = mdlMap->next; + + gcmkVERIFY_OK(_DestroyMdlMap(Mdl, mdlMap)); + + mdlMap = next; + } + + kfree(Mdl); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +static PLINUX_MDL_MAP +_CreateMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT ProcessID + ) +{ + PLINUX_MDL_MAP mdlMap; + + gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID); + + mdlMap = (PLINUX_MDL_MAP)kmalloc(sizeof(struct _LINUX_MDL_MAP), GFP_KERNEL | __GFP_NOWARN); + if (mdlMap == gcvNULL) + { + gcmkFOOTER_NO(); + return gcvNULL; + } + + mdlMap->pid = ProcessID; + mdlMap->vmaAddr = gcvNULL; + mdlMap->vma = gcvNULL; + + mdlMap->next = Mdl->maps; + Mdl->maps = mdlMap; + + gcmkFOOTER_ARG("0x%X", mdlMap); + return mdlMap; +} + +static gceSTATUS +_DestroyMdlMap( + IN PLINUX_MDL Mdl, + IN PLINUX_MDL_MAP MdlMap + ) +{ + PLINUX_MDL_MAP prevMdlMap; + + gcmkHEADER_ARG("Mdl=0x%X MdlMap=0x%X", Mdl, MdlMap); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(MdlMap != gcvNULL); + gcmkASSERT(Mdl->maps != gcvNULL); + + if (Mdl->maps == MdlMap) + { + Mdl->maps = MdlMap->next; + } + else + { + prevMdlMap = Mdl->maps; + + while (prevMdlMap->next != MdlMap) + { + prevMdlMap = prevMdlMap->next; + + gcmkASSERT(prevMdlMap != gcvNULL); + } + + prevMdlMap->next = MdlMap->next; + } + + kfree(MdlMap); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT ProcessID + ) +{ + PLINUX_MDL_MAP mdlMap; + + gcmkHEADER_ARG("Mdl=0x%X ProcessID=%d", Mdl, ProcessID); + if(Mdl == gcvNULL) + { + gcmkFOOTER_NO(); + return gcvNULL; + } + mdlMap = Mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->pid == ProcessID) + { + gcmkFOOTER_ARG("0x%X", mdlMap); + return mdlMap; + } + + mdlMap = mdlMap->next; + } + + gcmkFOOTER_NO(); + return gcvNULL; +} + +void +OnProcessExit( + IN gckOS Os, + IN gckKERNEL Kernel + ) +{ +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) +static inline int +is_vmalloc_addr( + void *Addr + ) +{ + unsigned long addr = (unsigned long)Addr; + + return addr >= VMALLOC_START && addr < VMALLOC_END; +} +#endif + +static void +_NonContiguousFree( + IN struct page ** Pages, + IN gctUINT32 NumPages + ) +{ + gctINT i; + + gcmkHEADER_ARG("Pages=0x%X, NumPages=%d", Pages, NumPages); + + gcmkASSERT(Pages != gcvNULL); + + for (i = 0; i < NumPages; i++) + { + __free_page(Pages[i]); + } + + if (is_vmalloc_addr(Pages)) + { + vfree(Pages); + } + else + { + kfree(Pages); + } + + gcmkFOOTER_NO(); +} + +static struct page ** +_NonContiguousAlloc( + IN gctUINT32 NumPages + ) +{ + struct page ** pages; + struct page *p; + gctINT i, size; + + gcmkHEADER_ARG("NumPages=%lu", NumPages); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) + if (NumPages > totalram_pages) +#else + if (NumPages > num_physpages) +#endif + { + gcmkFOOTER_NO(); + return gcvNULL; + } + + size = NumPages * sizeof(struct page *); + + pages = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); + + if (!pages) + { + pages = vmalloc(size); + + if (!pages) + { + gcmkFOOTER_NO(); + return gcvNULL; + } + } + + for (i = 0; i < NumPages; i++) + { + p = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN); + + if (!p) + { + _NonContiguousFree(pages, i); + gcmkFOOTER_NO(); + return gcvNULL; + } + + pages[i] = p; + } + + gcmkFOOTER_ARG("pages=0x%X", pages); + return pages; +} + +static inline struct page * +_NonContiguousToPage( + IN struct page ** Pages, + IN gctUINT32 Index + ) +{ + gcmkASSERT(Pages != gcvNULL); + return Pages[Index]; +} + +static inline unsigned long +_NonContiguousToPfn( + IN struct page ** Pages, + IN gctUINT32 Index + ) +{ + gcmkASSERT(Pages != gcvNULL); + return page_to_pfn(_NonContiguousToPage(Pages, Index)); +} + +static inline unsigned long +_NonContiguousToPhys( + IN struct page ** Pages, + IN gctUINT32 Index + ) +{ + gcmkASSERT(Pages != gcvNULL); + return page_to_phys(_NonContiguousToPage(Pages, Index)); +} + + +#if gcdUSE_NON_PAGED_MEMORY_CACHE + +static gctBOOL +_AddNonPagedMemoryCache( + gckOS Os, +#ifndef NO_DMA_COHERENT + gctINT Size, + gctSTRING Addr, + dma_addr_t DmaHandle +#else + long Order, + struct page * Page +#endif + ) +{ + gcsNonPagedMemoryCache *cache; + + if (Os->cacheSize >= gcdUSE_NON_PAGED_MEMORY_CACHE) + { + return gcvFALSE; + } + + /* Allocate the cache record */ + cache = (gcsNonPagedMemoryCache *)kmalloc(sizeof(gcsNonPagedMemoryCache), GFP_ATOMIC); + + if (cache == gcvNULL) return gcvFALSE; + +#ifndef NO_DMA_COHERENT + cache->size = Size; + cache->addr = Addr; + cache->dmaHandle = DmaHandle; +#else + cache->order = Order; + cache->page = Page; +#endif + + /* Add to list */ + if (Os->cacheHead == gcvNULL) + { + cache->prev = gcvNULL; + cache->next = gcvNULL; + Os->cacheHead = + Os->cacheTail = cache; + } + else + { + /* Add to the tail. */ + cache->prev = Os->cacheTail; + cache->next = gcvNULL; + Os->cacheTail->next = cache; + Os->cacheTail = cache; + } + + Os->cacheSize++; + + return gcvTRUE; +} + +#ifndef NO_DMA_COHERENT +static gctSTRING +_GetNonPagedMemoryCache( + gckOS Os, + gctINT Size, + dma_addr_t * DmaHandle + ) +#else +static struct page * +_GetNonPagedMemoryCache( + gckOS Os, + long Order + ) +#endif +{ + gcsNonPagedMemoryCache *cache; +#ifndef NO_DMA_COHERENT + gctSTRING addr; +#else + struct page * page; +#endif + + if (Os->cacheHead == gcvNULL) return gcvNULL; + + /* Find the right cache */ + cache = Os->cacheHead; + + while (cache != gcvNULL) + { +#ifndef NO_DMA_COHERENT + if (cache->size == Size) break; +#else + if (cache->order == Order) break; +#endif + + cache = cache->next; + } + + if (cache == gcvNULL) return gcvNULL; + + /* Remove the cache from list */ + if (cache == Os->cacheHead) + { + Os->cacheHead = cache->next; + + if (Os->cacheHead == gcvNULL) + { + Os->cacheTail = gcvNULL; + } + } + else + { + cache->prev->next = cache->next; + + if (cache == Os->cacheTail) + { + Os->cacheTail = cache->prev; + } + else + { + cache->next->prev = cache->prev; + } + } + + /* Destroy cache */ +#ifndef NO_DMA_COHERENT + addr = cache->addr; + *DmaHandle = cache->dmaHandle; +#else + page = cache->page; +#endif + + kfree(cache); + + Os->cacheSize--; + +#ifndef NO_DMA_COHERENT + return addr; +#else + return page; +#endif +} + +static void +_FreeAllNonPagedMemoryCache( + gckOS Os + ) +{ + gcsNonPagedMemoryCache *cache, *nextCache; + + MEMORY_LOCK(Os); + + cache = Os->cacheHead; + + while (cache != gcvNULL) + { + if (cache != Os->cacheTail) + { + nextCache = cache->next; + } + else + { + nextCache = gcvNULL; + } + + /* Remove the cache from list */ + if (cache == Os->cacheHead) + { + Os->cacheHead = cache->next; + + if (Os->cacheHead == gcvNULL) + { + Os->cacheTail = gcvNULL; + } + } + else + { + cache->prev->next = cache->next; + + if (cache == Os->cacheTail) + { + Os->cacheTail = cache->prev; + } + else + { + cache->next->prev = cache->prev; + } + } + +#ifndef NO_DMA_COHERENT + dma_free_coherent(gcvNULL, + cache->size, + cache->addr, + cache->dmaHandle); +#else + free_pages((unsigned long)page_address(cache->page), cache->order); +#endif + + kfree(cache); + + cache = nextCache; + } + + MEMORY_UNLOCK(Os); +} + +#endif /* gcdUSE_NON_PAGED_MEMORY_CACHE */ + +/******************************************************************************* +** +** gckOS_Construct +** +** Construct a new gckOS object. +** +** INPUT: +** +** gctPOINTER Context +** Pointer to the gckGALDEVICE class. +** +** OUTPUT: +** +** gckOS * Os +** Pointer to a variable that will hold the pointer to the gckOS object. +*/ +gceSTATUS +gckOS_Construct( + IN gctPOINTER Context, + OUT gckOS * Os + ) +{ + gckOS os; + gceSTATUS status; + + gcmkHEADER_ARG("Context=0x%X", Context); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Os != gcvNULL); + + /* Allocate the gckOS object. */ + os = (gckOS) kmalloc(gcmSIZEOF(struct _gckOS), GFP_KERNEL | __GFP_NOWARN); + + if (os == gcvNULL) + { + /* Out of memory. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Zero the memory. */ + gckOS_ZeroMemory(os, gcmSIZEOF(struct _gckOS)); + + /* Initialize the gckOS object. */ + os->object.type = gcvOBJ_OS; + + /* Set device device. */ + os->device = Context; + + /* IMPORTANT! No heap yet. */ + os->heap = gcvNULL; + + /* Initialize the memory lock. */ + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryLock)); + gcmkONERROR(gckOS_CreateMutex(os, &os->memoryMapLock)); + + /* Create debug lock mutex. */ + gcmkONERROR(gckOS_CreateMutex(os, &os->debugLock)); + + + os->mdlHead = os->mdlTail = gcvNULL; + + /* Get the kernel process ID. */ + gcmkONERROR(gckOS_GetProcessID(&os->kernelProcessID)); + + /* + * Initialize the signal manager. + * It creates the signals to be used in + * the user space. + */ + + /* Initialize mutex. */ + gcmkONERROR( + gckOS_CreateMutex(os, &os->signal.lock)); + + /* Initialize the signal table. */ + os->signal.table = + kmalloc(gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT, GFP_KERNEL | __GFP_NOWARN); + + if (os->signal.table == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + gckOS_ZeroMemory(os->signal.table, + gcmSIZEOF(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + + /* Set the signal table length. */ + os->signal.tableLen = USER_SIGNAL_TABLE_LEN_INIT; + + /* The table is empty. */ + os->signal.unused = os->signal.tableLen; + + /* Initial signal ID. */ + os->signal.currentID = 0; + +#if gcdUSE_NON_PAGED_MEMORY_CACHE + os->cacheSize = 0; + os->cacheHead = gcvNULL; + os->cacheTail = gcvNULL; +#endif + + /* Create a workqueue for os timer. */ + os->workqueue = create_singlethread_workqueue("galcore workqueue"); + + if (os->workqueue == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the gckOS object. */ + *Os = os; + + /* Success. */ + gcmkFOOTER_ARG("*Os=0x%X", *Os); + return gcvSTATUS_OK; + +OnError: + /* Roll back any allocation. */ + if (os->signal.table != gcvNULL) + { + kfree(os->signal.table); + } + + if (os->signal.lock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->signal.lock)); + } + + if (os->heap != gcvNULL) + { + gcmkVERIFY_OK( + gckHEAP_Destroy(os->heap)); + } + + if (os->memoryMapLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryMapLock)); + } + + if (os->memoryLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->memoryLock)); + } + + if (os->debugLock != gcvNULL) + { + gcmkVERIFY_OK( + gckOS_DeleteMutex(os, os->debugLock)); + } + + if (os->workqueue != gcvNULL) + { + destroy_workqueue(os->workqueue); + } + + kfree(os); + + /* Return the error. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_Destroy +** +** Destroy an gckOS object. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object that needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Destroy( + IN gckOS Os + ) +{ + gckHEAP heap; + + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + +#if gcdUSE_NON_PAGED_MEMORY_CACHE + _FreeAllNonPagedMemoryCache(Os); +#endif + + /* + * Destroy the signal manager. + */ + + /* Destroy the mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->signal.lock)); + + /* Free the signal table. */ + kfree(Os->signal.table); + + if (Os->heap != gcvNULL) + { + /* Mark gckHEAP as gone. */ + heap = Os->heap; + Os->heap = gcvNULL; + + /* Destroy the gckHEAP object. */ + gcmkVERIFY_OK(gckHEAP_Destroy(heap)); + } + + /* Destroy the memory lock. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryMapLock)); + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->memoryLock)); + + /* Destroy debug lock mutex. */ + gcmkVERIFY_OK(gckOS_DeleteMutex(Os, Os->debugLock)); + + /* Wait for all works done. */ + flush_workqueue(Os->workqueue); + + /* Destory work queue. */ + destroy_workqueue(Os->workqueue); + + /* Flush the debug cache. */ + gcmkDEBUGFLUSH(~0U); + + /* Mark the gckOS object as unknown. */ + Os->object.type = gcvOBJ_UNKNOWN; + + /* Free the gckOS object. */ + kfree(Os); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#ifdef NO_DMA_COHERENT +static gctSTRING +_CreateKernelVirtualMapping( + IN struct page * Page, + IN gctINT NumPages + ) +{ + gctSTRING addr = 0; + +#if gcdNONPAGED_MEMORY_CACHEABLE + addr = page_address(Page); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + struct page ** pages; + gctINT i; + + pages = kmalloc(sizeof(struct page *) * NumPages, GFP_KERNEL | __GFP_NOWARN); + + if (!pages) + { + return gcvNULL; + } + + for (i = 0; i < NumPages; i++) + { + pages[i] = nth_page(Page, i); + } + + /* ioremap() can't work on system memory since 2.6.38. */ + addr = vmap(pages, NumPages, 0, gcmkNONPAGED_MEMROY_PROT(PAGE_KERNEL)); + + kfree(pages); +#else + addr = gcmkIOREMAP(page_to_phys(Page), NumPages * PAGE_SIZE); +#endif + + return addr; +} + +static void +_DestoryKernelVirtualMapping( + IN gctSTRING Addr + ) +{ +#if !gcdNONPAGED_MEMORY_CACHEABLE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38) + vunmap(Addr); +# else + iounmap(Addr); +# endif +#endif +} +#endif + +/******************************************************************************* +** +** gckOS_Allocate +** +** Allocate memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_Allocate( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Do we have a heap? */ + if (Os->heap != gcvNULL) + { + /* Allocate from the heap. */ + gcmkONERROR(gckHEAP_Allocate(Os->heap, Bytes, Memory)); + } + else + { + gcmkONERROR(gckOS_AllocateMemory(Os, Bytes, Memory)); + } + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%X", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_Free +** +** Free allocated memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Free( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Memory=0x%X", Os, Memory); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Do we have a heap? */ + if (Os->heap != gcvNULL) + { + /* Free from the heap. */ + gcmkONERROR(gckHEAP_Free(Os->heap, Memory)); + } + else + { + gcmkONERROR(gckOS_FreeMemory(Os, Memory)); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AllocateMemory +** +** Allocate memory wrapper. +** +** INPUT: +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the allocated memory location. +*/ +gceSTATUS +gckOS_AllocateMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Memory + ) +{ + gctPOINTER memory; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + if (Bytes > PAGE_SIZE) + { + memory = (gctPOINTER) vmalloc(Bytes); + } + else + { + memory = (gctPOINTER) kmalloc(Bytes, GFP_KERNEL | __GFP_NOWARN); + } + + if (memory == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Return pointer to the memory allocation. */ + *Memory = memory; + + /* Success. */ + gcmkFOOTER_ARG("*Memory=0x%X", *Memory); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeMemory +** +** Free allocated memory wrapper. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory allocation to free. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeMemory( + IN gckOS Os, + IN gctPOINTER Memory + ) +{ + gcmkHEADER_ARG("Memory=0x%X", Memory); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + + /* Free the memory from the OS pool. */ + if (is_vmalloc_addr(Memory)) + { + vfree(Memory); + } + else + { + kfree(Memory); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapMemory +** +** Map physical memory into the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Memory +** Pointer to a variable that will hold the logical address of the +** mapped memory. +*/ +gceSTATUS +gckOS_MapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, _GetProcessID()); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, _GetProcessID()); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (char *)do_mmap_pgoff(gcvNULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (IS_ERR(mdlMap->vmaAddr)) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): do_mmap_pgoff error", + __FUNCTION__, __LINE__ + ); + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): mdl->numPages: %d mdl->vmaAddr: 0x%X", + __FUNCTION__, __LINE__, + mdl->numPages, + mdlMap->vmaAddr + ); + + mdlMap->vmaAddr = gcvNULL; + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (!mdlMap->vma) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): find_vma error.", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + up_write(¤t->mm->mmap_sem); + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); + return gcvSTATUS_OUT_OF_RESOURCES; + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(Os->device->dev, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): dma_mmap_coherent error.", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); + return gcvSTATUS_OUT_OF_RESOURCES; + } +#else +#if !gcdPAGED_MEMORY_CACHEABLE + mdlMap->vma->vm_page_prot = gcmkPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; +# endif + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages*PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): remap_pfn_range error.", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); + return gcvSTATUS_OUT_OF_RESOURCES; + } +#endif + + up_write(¤t->mm->mmap_sem); + } + + MEMORY_UNLOCK(Os); + + *Logical = mdlMap->vmaAddr; + + gcmkFOOTER_ARG("*Logical=0x%X", *Logical); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapMemory +** +** Unmap physical memory out of the current process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** gctPOINTER Memory +** Pointer to a previously mapped memory region. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X", + Os, Physical, Bytes, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + gckOS_UnmapMemoryEx(Os, Physical, Bytes, Logical, _GetProcessID()); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_UnmapMemoryEx +** +** Unmap physical memory in the specified process. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Start of physical address memory. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** gctPOINTER Memory +** Pointer to a previously mapped memory region. +** +** gctUINT32 PID +** Pid of the process that opened the device and mapped this memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapMemoryEx( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical, + IN gctUINT32 PID + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu Logical=0x%X PID=%d", + Os, Physical, Bytes, Logical, PID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(PID != 0); + + MEMORY_LOCK(Os); + + if (Logical) + { + mdlMap = FindMdlMap(mdl, PID); + + if (mdlMap == gcvNULL || mdlMap->vmaAddr == gcvNULL) + { + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)Logical, mdl->numPages*PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + else + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): can't find the task with pid->%d. No unmapping", + __FUNCTION__, __LINE__, + mdlMap->pid + ); + } + + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocateNonPagedMemory +** +** Allocate a number of pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to a variable that holds the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that hold the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that will hold the physical address of the +** allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that will hold the logical address of the +** allocation. +*/ +gceSTATUS +gckOS_AllocateNonPagedMemory( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + gctSIZE_T bytes; + gctINT numPages; + PLINUX_MDL mdl = gcvNULL; + PLINUX_MDL_MAP mdlMap = gcvNULL; + gctSTRING addr; +#ifdef NO_DMA_COHERENT + struct page * page; + long size, order; + gctPOINTER vaddr; +#endif + gctBOOL locked = gcvFALSE; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu", + Os, InUserSpace, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes != gcvNULL); + gcmkVERIFY_ARGUMENT(*Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Align number of bytes to page size. */ + bytes = gcmALIGN(*Bytes, PAGE_SIZE); + + /* Get total number of pages.. */ + numPages = GetPageCount(bytes, 0); + + /* Allocate mdl+vector structure */ + mdl = _CreateMdl(_GetProcessID()); + if (mdl == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + mdl->pagedMem = 0; + mdl->numPages = numPages; + + MEMORY_LOCK(Os); + locked = gcvTRUE; + +#ifndef NO_DMA_COHERENT +#if gcdUSE_NON_PAGED_MEMORY_CACHE + addr = _GetNonPagedMemoryCache(Os, + mdl->numPages * PAGE_SIZE, + &mdl->dmaHandle); + + if (addr == gcvNULL) +#endif + { + addr = dma_alloc_coherent(Os->device->dev, + mdl->numPages * PAGE_SIZE, + &mdl->dmaHandle, + GFP_KERNEL | __GFP_NOWARN); + } +#else + size = mdl->numPages * PAGE_SIZE; + order = get_order(size); +#if gcdUSE_NON_PAGED_MEMORY_CACHE + page = _GetNonPagedMemoryCache(Os, order); + + if (page == gcvNULL) +#endif + { + page = alloc_pages(GFP_KERNEL | __GFP_NOWARN, order); + } + + if (page == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + vaddr = (gctPOINTER)page_address(page); + addr = _CreateKernelVirtualMapping(page, mdl->numPages); + mdl->dmaHandle = virt_to_phys(vaddr); + mdl->kaddr = vaddr; + mdl->u.contiguousPages = page; + + /* Cache invalidate. */ + dma_sync_single_for_device( + gcvNULL, + page_to_phys(page), + bytes, + DMA_FROM_DEVICE); + + while (size > 0) + { + SetPageReserved(virt_to_page(vaddr)); + + vaddr += PAGE_SIZE; + size -= PAGE_SIZE; + } +#endif + + if (addr == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + if ((Os->device->baseAddress & 0x80000000) != (mdl->dmaHandle & 0x80000000)) + { + mdl->dmaHandle = (mdl->dmaHandle & ~0x80000000) + | (Os->device->baseAddress & 0x80000000); + } + + mdl->addr = addr; + + /* Return allocated memory. */ + *Bytes = bytes; + *Physical = (gctPHYS_ADDR) mdl; + + if (InUserSpace) + { + mdlMap = _CreateMdlMap(mdl, _GetProcessID()); + + if (mdlMap == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Only after mmap this will be valid. */ + + /* We need to map this to user space. */ + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING) do_mmap_pgoff(gcvNULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + if (IS_ERR(mdlMap->vmaAddr)) + { + gcmkTRACE_ZONE( + gcvLEVEL_WARNING, gcvZONE_OS, + "%s(%d): do_mmap_pgoff error", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + up_write(¤t->mm->mmap_sem); + + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_WARNING, gcvZONE_OS, + "%s(%d): find_vma error", + __FUNCTION__, __LINE__ + ); + + up_write(¤t->mm->mmap_sem); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + +#ifndef NO_DMA_COHERENT + if (dma_mmap_coherent(Os->device->dev, + mdlMap->vma, + mdl->addr, + mdl->dmaHandle, + mdl->numPages * PAGE_SIZE) < 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_WARNING, gcvZONE_OS, + "%s(%d): dma_mmap_coherent error", + __FUNCTION__, __LINE__ + ); + + up_write(¤t->mm->mmap_sem); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } +#else + mdlMap->vma->vm_page_prot = gcmkNONPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); + mdlMap->vma->vm_flags |= VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED; + mdlMap->vma->vm_pgoff = 0; + + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + mdl->dmaHandle >> PAGE_SHIFT, + mdl->numPages * PAGE_SIZE, + mdlMap->vma->vm_page_prot)) + { + gcmkTRACE_ZONE( + gcvLEVEL_WARNING, gcvZONE_OS, + "%s(%d): remap_pfn_range error", + __FUNCTION__, __LINE__ + ); + + up_write(¤t->mm->mmap_sem); + + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } +#endif /* NO_DMA_COHERENT */ + + up_write(¤t->mm->mmap_sem); + + *Logical = mdlMap->vmaAddr; + } + else + { + *Logical = (gctPOINTER)mdl->addr; + } + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to the tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X", + *Bytes, *Physical, *Logical); + return gcvSTATUS_OK; + +OnError: + if (mdlMap != gcvNULL) + { + /* Free LINUX_MDL_MAP. */ + gcmkVERIFY_OK(_DestroyMdlMap(mdl, mdlMap)); + } + + if (mdl != gcvNULL) + { + /* Free LINUX_MDL. */ + gcmkVERIFY_OK(_DestroyMdl(mdl)); + } + + if (locked) + { + /* Unlock memory. */ + MEMORY_UNLOCK(Os); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeNonPagedMemory +** +** Free previously allocated and mapped pages from non-paged memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes allocated. +** +** gctPHYS_ADDR Physical +** Physical address of the allocated memory. +** +** gctPOINTER Logical +** Logical address of the allocated memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS gckOS_FreeNonPagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + struct task_struct * task; +#ifdef NO_DMA_COHERENT + unsigned size; + gctPOINTER vaddr; +#endif /* NO_DMA_COHERENT */ + + gcmkHEADER_ARG("Os=0x%X Bytes=%lu Physical=0x%X Logical=0x%X", + Os, Bytes, Physical, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Convert physical address into a pointer to a MDL. */ + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + +#ifndef NO_DMA_COHERENT +#if gcdUSE_NON_PAGED_MEMORY_CACHE + if (!_AddNonPagedMemoryCache(Os, + mdl->numPages * PAGE_SIZE, + mdl->addr, + mdl->dmaHandle)) +#endif + { + dma_free_coherent(Os->device->dev, + mdl->numPages * PAGE_SIZE, + mdl->addr, + mdl->dmaHandle); + } +#else + size = mdl->numPages * PAGE_SIZE; + vaddr = mdl->kaddr; + + while (size > 0) + { + ClearPageReserved(virt_to_page(vaddr)); + + vaddr += PAGE_SIZE; + size -= PAGE_SIZE; + } + +#if gcdUSE_NON_PAGED_MEMORY_CACHE + if (!_AddNonPagedMemoryCache(Os, + get_order(mdl->numPages * PAGE_SIZE), + virt_to_page(mdl->kaddr))) +#endif + { + free_pages((unsigned long)mdl->kaddr, get_order(mdl->numPages * PAGE_SIZE)); + } + + _DestoryKernelVirtualMapping(mdl->addr); +#endif /* NO_DMA_COHERENT */ + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if (mdlMap->vmaAddr != gcvNULL) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + + if (do_munmap(task->mm, + (unsigned long)mdlMap->vmaAddr, + mdl->numPages * PAGE_SIZE) < 0) + { + gcmkTRACE_ZONE( + gcvLEVEL_WARNING, gcvZONE_OS, + "%s(%d): do_munmap failed", + __FUNCTION__, __LINE__ + ); + } + + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + /* Remove the node from global list.. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_ReadRegister +** +** Read data from a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** OUTPUT: +** +** gctUINT32 * Data +** Pointer to a variable that receives the data read from the register. +*/ +gceSTATUS +gckOS_ReadRegister( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ) +{ + return gckOS_ReadRegisterEx(Os, gcvCORE_MAJOR, Address, Data); +} + +gceSTATUS +gckOS_ReadRegisterEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + OUT gctUINT32 * Data + ) +{ + gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X", Os, Core, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Data != gcvNULL); + + *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address); + + /* Success. */ + gcmkFOOTER_ARG("*Data=0x%08x", *Data); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_WriteRegister +** +** Write data to a register. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Address of register. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WriteRegister( + IN gckOS Os, + IN gctUINT32 Address, + IN gctUINT32 Data + ) +{ + return gckOS_WriteRegisterEx(Os, gcvCORE_MAJOR, Address, Data); +} + +gceSTATUS +gckOS_WriteRegisterEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + IN gctUINT32 Data + ) +{ + gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%X Data=0x%08x", Os, Core, Address, Data); + + writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPageSize +** +** Get the system's page size. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctSIZE_T * PageSize +** Pointer to a variable that will receive the system's page size. +*/ +gceSTATUS gckOS_GetPageSize( + IN gckOS Os, + OUT gctSIZE_T * PageSize + ) +{ + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(PageSize != gcvNULL); + + /* Return the page size. */ + *PageSize = (gctSIZE_T) PAGE_SIZE; + + /* Success. */ + gcmkFOOTER_ARG("*PageSize", *PageSize); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddress +** +** Get the physical system address of a corresponding virtual address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS +gckOS_GetPhysicalAddress( + IN gckOS Os, + IN gctPOINTER Logical, + OUT gctUINT32 * Address + ) +{ + gceSTATUS status; + gctUINT32 processID; + + gcmkHEADER_ARG("Os=0x%X Logical=0x%X", Os, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Get current process ID. */ + processID = _GetProcessID(); + + /* Route through other function. */ + gcmkONERROR( + gckOS_GetPhysicalAddressProcess(Os, Logical, processID, Address)); + + /* Success. */ + gcmkFOOTER_ARG("*Address=0x%08x", *Address); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdSECURE_USER +static gceSTATUS +gckOS_AddMapping( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + gcsUSER_MAPPING_PTR map; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu", + Os, Physical, Logical, Bytes); + + gcmkONERROR(gckOS_Allocate(Os, + gcmSIZEOF(gcsUSER_MAPPING), + (gctPOINTER *) &map)); + + map->next = Os->userMap; + map->physical = Physical - Os->device->baseAddress; + map->logical = Logical; + map->bytes = Bytes; + map->start = (gctINT8_PTR) Logical; + map->end = map->start + Bytes; + + Os->userMap = map; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +static gceSTATUS +gckOS_RemoveMapping( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + gcsUSER_MAPPING_PTR map, prev; + + gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes); + + for (map = Os->userMap, prev = gcvNULL; map != gcvNULL; map = map->next) + { + if ((map->logical == Logical) + && (map->bytes == Bytes) + ) + { + break; + } + + prev = map; + } + + if (map == gcvNULL) + { + gcmkONERROR(gcvSTATUS_INVALID_ADDRESS); + } + + if (prev == gcvNULL) + { + Os->userMap = map->next; + } + else + { + prev->next = map->next; + } + + gcmkONERROR(gcmkOS_SAFE_FREE(Os, map)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} +#endif + +static gceSTATUS +_ConvertLogical2Physical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT32 ProcessID, + IN PLINUX_MDL Mdl, + OUT gctUINT32_PTR Physical + ) +{ + gctINT8_PTR base, vBase; + gctUINT32 offset; + PLINUX_MDL_MAP map; + gcsUSER_MAPPING_PTR userMap; + + base = (Mdl == gcvNULL) ? gcvNULL : (gctINT8_PTR) Mdl->addr; + + /* Check for the logical address match. */ + if ((base != gcvNULL) + && ((gctINT8_PTR) Logical >= base) + && ((gctINT8_PTR) Logical < base + Mdl->numPages * PAGE_SIZE) + ) + { + offset = (gctINT8_PTR) Logical - base; + + if (Mdl->dmaHandle != 0) + { + /* The memory was from coherent area. */ + *Physical = (gctUINT32) Mdl->dmaHandle + offset; + } + else if (Mdl->pagedMem && !Mdl->contiguous) + { + /* paged memory is not mapped to kernel space. */ + return gcvSTATUS_INVALID_ADDRESS; + } + else + { + *Physical = gcmPTR2INT(virt_to_phys(base)) + offset; + } + + return gcvSTATUS_OK; + } + + /* Walk user maps. */ + for (userMap = Os->userMap; userMap != gcvNULL; userMap = userMap->next) + { + if (((gctINT8_PTR) Logical >= userMap->start) + && ((gctINT8_PTR) Logical < userMap->end) + ) + { + *Physical = userMap->physical + + (gctUINT32) ((gctINT8_PTR) Logical - userMap->start); + + return gcvSTATUS_OK; + } + } + + if (ProcessID != Os->kernelProcessID) + { + map = FindMdlMap(Mdl, (gctINT) ProcessID); + vBase = (map == gcvNULL) ? gcvNULL : (gctINT8_PTR) map->vmaAddr; + + /* Is the given address within that range. */ + if ((vBase != gcvNULL) + && ((gctINT8_PTR) Logical >= vBase) + && ((gctINT8_PTR) Logical < vBase + Mdl->numPages * PAGE_SIZE) + ) + { + offset = (gctINT8_PTR) Logical - vBase; + + if (Mdl->dmaHandle != 0) + { + /* The memory was from coherent area. */ + *Physical = (gctUINT32) Mdl->dmaHandle + offset; + } + else if (Mdl->pagedMem && !Mdl->contiguous) + { + *Physical = _NonContiguousToPhys(Mdl->u.nonContiguousPages, offset/PAGE_SIZE); + } + else + { + *Physical = page_to_phys(Mdl->u.contiguousPages) + offset; + } + + return gcvSTATUS_OK; + } + } + + /* Address not yet found. */ + return gcvSTATUS_INVALID_ADDRESS; +} + +/******************************************************************************* +** +** gckOS_GetPhysicalAddressProcess +** +** Get the physical system address of a corresponding virtual address for a +** given process. +** +** INPUT: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctPOINTER Logical +** Logical address. +** +** gctUINT32 ProcessID +** Process ID. +** +** OUTPUT: +** +** gctUINT32 * Address +** Poinetr to a variable that receives the 32-bit physical adress. +*/ +gceSTATUS +gckOS_GetPhysicalAddressProcess( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctUINT32 ProcessID, + OUT gctUINT32 * Address + ) +{ + PLINUX_MDL mdl; + gctINT8_PTR base; + gceSTATUS status = gcvSTATUS_INVALID_ADDRESS; + + gcmkHEADER_ARG("Os=0x%X Logical=0x%X ProcessID=%d", Os, Logical, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + MEMORY_LOCK(Os); + + /* First try the contiguous memory pool. */ + if (Os->device->contiguousMapped) + { + base = (gctINT8_PTR) Os->device->contiguousBase; + + if (((gctINT8_PTR) Logical >= base) + && ((gctINT8_PTR) Logical < base + Os->device->contiguousSize) + ) + { + /* Convert logical address into physical. */ + *Address = Os->device->contiguousVidMem->baseAddress + + (gctINT8_PTR) Logical - base; + status = gcvSTATUS_OK; + } + } + else + { + /* Try the contiguous memory pool. */ + mdl = (PLINUX_MDL) Os->device->contiguousPhysical; + status = _ConvertLogical2Physical(Os, + Logical, + ProcessID, + mdl, + Address); + } + + if (gcmIS_ERROR(status)) + { + /* Walk all MDLs. */ + for (mdl = Os->mdlHead; mdl != gcvNULL; mdl = mdl->next) + { + /* Try this MDL. */ + status = _ConvertLogical2Physical(Os, + Logical, + ProcessID, + mdl, + Address); + if (gcmIS_SUCCESS(status)) + { + break; + } + } + } + + MEMORY_UNLOCK(Os); + + gcmkONERROR(status); + + if (Os->device->baseAddress != 0) + { + /* Subtract base address to get a GPU physical address. */ + gcmkASSERT(*Address >= Os->device->baseAddress); + *Address -= Os->device->baseAddress; + } + + /* Success. */ + gcmkFOOTER_ARG("*Address=0x%08x", *Address); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_MapPhysical +** +** Map a physical address into kernel space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Physical +** Physical address of the memory to map. +** +** gctSIZE_T Bytes +** Number of bytes to map. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the base address of the mapped +** memory. +*/ +gceSTATUS +gckOS_MapPhysical( + IN gckOS Os, + IN gctUINT32 Physical, + IN gctSIZE_T Bytes, + OUT gctPOINTER * Logical + ) +{ + gctPOINTER logical; + PLINUX_MDL mdl; + gctUINT32 physical; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + MEMORY_LOCK(Os); + + /* Compute true physical address (before subtraction of the baseAddress). */ + physical = Physical + Os->device->baseAddress; + + /* Go through our mapping to see if we know this physical address already. */ + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->dmaHandle != 0) + { + if ((physical >= mdl->dmaHandle) + && (physical < mdl->dmaHandle + mdl->numPages * PAGE_SIZE) + ) + { + *Logical = mdl->addr + (physical - mdl->dmaHandle); + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Map memory as cached memory. */ + request_mem_region(physical, Bytes, "MapRegion"); + logical = (gctPOINTER) ioremap_nocache(physical, Bytes); + + if (logical == gcvNULL) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): Failed to ioremap", + __FUNCTION__, __LINE__ + ); + + MEMORY_UNLOCK(Os); + + /* Out of resources. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_RESOURCES); + return gcvSTATUS_OUT_OF_RESOURCES; + } + + /* Return pointer to mapped memory. */ + *Logical = logical; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_ARG("*Logical=0x%X", *Logical); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapPhysical +** +** Unmap a previously mapped memory region from kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Logical +** Pointer to the base address of the memory to unmap. +** +** gctSIZE_T Bytes +** Number of bytes to unmap. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapPhysical( + IN gckOS Os, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl; + + gcmkHEADER_ARG("Os=0x%X Logical=0x%X Bytes=%lu", Os, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + MEMORY_LOCK(Os); + + mdl = Os->mdlHead; + + while (mdl != gcvNULL) + { + if (mdl->addr != gcvNULL) + { + if (Logical >= (gctPOINTER)mdl->addr + && Logical < (gctPOINTER)((gctSTRING)mdl->addr + mdl->numPages * PAGE_SIZE)) + { + break; + } + } + + mdl = mdl->next; + } + + if (mdl == gcvNULL) + { + /* Unmap the memory. */ + iounmap(Logical); + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CreateMutex +** +** Create a new mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Mutex +** Pointer to a variable that will hold a pointer to the mutex. +*/ +gceSTATUS +gckOS_CreateMutex( + IN gckOS Os, + OUT gctPOINTER * Mutex + ) +{ + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); + + /* Allocate a FAST_MUTEX structure. */ + *Mutex = (gctPOINTER)kmalloc(sizeof(struct semaphore), GFP_KERNEL | __GFP_NOWARN); + + if (*Mutex == gcvNULL) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + /* Initialize the semaphore.. Come up in unlocked state. */ + sema_init(*Mutex, 1); + + /* Return status. */ + gcmkFOOTER_ARG("*Mutex=0x%X", *Mutex); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DeleteMutex +** +** Delete a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mute to be deleted. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DeleteMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + gcmkHEADER_ARG("Os=0x%X Mutex=0x%X", Os, Mutex); + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); + + /* Delete the fast mutex. */ + kfree(Mutex); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AcquireMutex +** +** Acquire a mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be acquired. +** +** gctUINT32 Timeout +** Timeout value specified in milliseconds. +** Specify the value of gcvINFINITE to keep the thread suspended +** until the mutex has been acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireMutex( + IN gckOS Os, + IN gctPOINTER Mutex, + IN gctUINT32 Timeout + ) +{ +#if gcdDETECT_TIMEOUT + gctUINT32 timeout; +#endif + + gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x Timeout=%u", Os, Mutex, Timeout); + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); + +#if gcdDETECT_TIMEOUT + timeout = 0; + + for (;;) + { + /* Try to acquire the mutex. */ + if (!down_trylock((struct semaphore *) Mutex)) + { + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + /* Advance the timeout. */ + timeout += 1; + + if (Timeout == gcvINFINITE) + { + if (timeout == gcdINFINITE_TIMEOUT) + { + gctUINT32 dmaAddress1, dmaAddress2; + gctUINT32 dmaState1, dmaState2; + + dmaState1 = dmaState2 = + dmaAddress1 = dmaAddress2 = 0; + + /* Verify whether DMA is running. */ + gcmkVERIFY_OK(_VerifyDMA( + Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2 + )); + +#if gcdDETECT_DMA_ADDRESS + /* Dump only if DMA appears stuck. */ + if ( + (dmaAddress1 == dmaAddress2) +#if gcdDETECT_DMA_STATE + && (dmaState1 == dmaState2) +# endif + ) +# endif + { + gcmkVERIFY_OK(_DumpGPUState(Os, gcvCORE_MAJOR)); + + gcmkPRINT( + "%s(%d): mutex 0x%X; forced message flush.", + __FUNCTION__, __LINE__, Mutex + ); + + /* Flush the debug cache. */ + gcmkDEBUGFLUSH(dmaAddress2); + } + + timeout = 0; + } + } + else + { + /* Timedout? */ + if (timeout >= Timeout) + { + break; + } + } + + /* Wait for 1 millisecond. */ + gcmkVERIFY_OK(gckOS_Delay(Os, 1)); + } +#else + if (Timeout == gcvINFINITE) + { + down((struct semaphore *) Mutex); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + for (;;) + { + /* Try to acquire the mutex. */ + if (!down_trylock((struct semaphore *) Mutex)) + { + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + if (Timeout-- == 0) + { + break; + } + + /* Wait for 1 millisecond. */ + gcmkVERIFY_OK(gckOS_Delay(Os, 1)); + } +#endif + + /* Timeout. */ + gcmkFOOTER_ARG("status=%d", gcvSTATUS_TIMEOUT); + return gcvSTATUS_TIMEOUT; +} + +/******************************************************************************* +** +** gckOS_ReleaseMutex +** +** Release an acquired mutex. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Mutex +** Pointer to the mutex to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_ReleaseMutex( + IN gckOS Os, + IN gctPOINTER Mutex + ) +{ + gcmkHEADER_ARG("Os=0x%X Mutex=0x%0x", Os, Mutex); + + /* Validate the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Mutex != gcvNULL); + + /* Release the fast mutex. */ + up((struct semaphore *) Mutex); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchange +** +** Atomically exchange a pair of 32-bit values. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctINT32_PTR Target +** Pointer to the 32-bit value to exchange. +** +** IN gctINT32 NewValue +** Specifies a new value for the 32-bit value pointed to by Target. +** +** OUT gctINT32_PTR OldValue +** The old value of the 32-bit value pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchange( + IN gckOS Os, + IN OUT gctUINT32_PTR Target, + IN gctUINT32 NewValue, + OUT gctUINT32_PTR OldValue + ) +{ + gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=%u", Os, Target, NewValue); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of 32-bit values. */ + *OldValue = (gctUINT32) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + gcmkFOOTER_ARG("*OldValue=%u", *OldValue); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomicExchangePtr +** +** Atomically exchange a pair of pointers. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** IN OUT gctPOINTER * Target +** Pointer to the 32-bit value to exchange. +** +** IN gctPOINTER NewValue +** Specifies a new value for the pointer pointed to by Target. +** +** OUT gctPOINTER * OldValue +** The old value of the pointer pointed to by Target. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomicExchangePtr( + IN gckOS Os, + IN OUT gctPOINTER * Target, + IN gctPOINTER NewValue, + OUT gctPOINTER * OldValue + ) +{ + gcmkHEADER_ARG("Os=0x%X Target=0x%X NewValue=0x%X", Os, Target, NewValue); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + /* Exchange the pair of pointers. */ + *OldValue = (gctPOINTER) atomic_xchg((atomic_t *) Target, (int) NewValue); + + /* Success. */ + gcmkFOOTER_ARG("*OldValue=0x%X", *OldValue); + return gcvSTATUS_OK; +} + +#if gcdSMP +/******************************************************************************* +** +** gckOS_AtomicSetMask +** +** Atomically set mask to Atom +** +** INPUT: +** IN OUT gctPOINTER Atom +** Pointer to the atom to set. +** +** IN gctUINT32 Mask +** Mask to set. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomSetMask( + IN gctPOINTER Atom, + IN gctUINT32 Mask + ) +{ + gctUINT32 oval, nval; + + gcmkHEADER_ARG("Atom=0x%0x", Atom); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + do + { + oval = atomic_read((atomic_t *) Atom); + nval = oval | Mask; + } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomClearMask +** +** Atomically clear mask from Atom +** +** INPUT: +** IN OUT gctPOINTER Atom +** Pointer to the atom to clear. +** +** IN gctUINT32 Mask +** Mask to clear. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomClearMask( + IN gctPOINTER Atom, + IN gctUINT32 Mask + ) +{ + gctUINT32 oval, nval; + + gcmkHEADER_ARG("Atom=0x%0x", Atom); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + do + { + oval = atomic_read((atomic_t *) Atom); + nval = oval & ~Mask; + } while (atomic_cmpxchg((atomic_t *) Atom, oval, nval) != oval); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} +#endif + +/******************************************************************************* +** +** gckOS_AtomConstruct +** +** Create an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Atom +** Pointer to a variable receiving the constructed atom. +*/ +gceSTATUS +gckOS_AtomConstruct( + IN gckOS Os, + OUT gctPOINTER * Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Allocate the atom. */ + gcmkONERROR(gckOS_Allocate(Os, gcmSIZEOF(atomic_t), Atom)); + + /* Initialize the atom. */ + atomic_set((atomic_t *) *Atom, 0); + + /* Success. */ + gcmkFOOTER_ARG("*Atom=0x%X", *Atom); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomDestroy +** +** Destroy an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom to destroy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomDestroy( + IN gckOS Os, + OUT gctPOINTER Atom + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Free the atom. */ + gcmkONERROR(gcmkOS_SAFE_FREE(Os, Atom)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AtomGet +** +** Get the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable the receives the value of the atom. +*/ +gceSTATUS +gckOS_AtomGet( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Return the current value of atom. */ + *Value = atomic_read((atomic_t *) Atom); + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomSet +** +** Set the 32-bit value protected by an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** gctINT32 Value +** The value of the atom. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AtomSet( + IN gckOS Os, + IN gctPOINTER Atom, + IN gctINT32 Value + ) +{ + gcmkHEADER_ARG("Os=0x%X Atom=0x%0x Value=%d", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Set the current value of atom. */ + atomic_set((atomic_t *) Atom, Value); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomIncrement +** +** Atomically increment the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable that receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomIncrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Increment the atom. */ + *Value = atomic_inc_return((atomic_t *) Atom) - 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AtomDecrement +** +** Atomically decrement the 32-bit integer value inside an atom. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctPOINTER Atom +** Pointer to the atom. +** +** OUTPUT: +** +** gctINT32_PTR Value +** Pointer to a variable that receives the original value of the atom. +*/ +gceSTATUS +gckOS_AtomDecrement( + IN gckOS Os, + IN gctPOINTER Atom, + OUT gctINT32_PTR Value + ) +{ + gcmkHEADER_ARG("Os=0x%X Atom=0x%0x", Os, Atom); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Atom != gcvNULL); + + /* Decrement the atom. */ + *Value = atomic_dec_return((atomic_t *) Atom) + 1; + + /* Success. */ + gcmkFOOTER_ARG("*Value=%d", *Value); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Delay +** +** Delay execution of the current thread for a number of milliseconds. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Delay +** Delay to sleep, specified in milliseconds. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Delay( + IN gckOS Os, + IN gctUINT32 Delay + ) +{ + struct timeval now; + unsigned long jiffies; + + gcmkHEADER_ARG("Os=0x%X Delay=%u", Os, Delay); + + if (Delay > 0) + { + /* Convert milliseconds into seconds and microseconds. */ + now.tv_sec = Delay / 1000; + now.tv_usec = (Delay % 1000) * 1000; + + /* Convert timeval to jiffies. */ + jiffies = timeval_to_jiffies(&now); + + /* Schedule timeout. */ + schedule_timeout_interruptible(jiffies); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetTicks +** +** Get the number of milliseconds since the system started. +** +** INPUT: +** +** OUTPUT: +** +** gctUINT32_PTR Time +** Pointer to a variable to get time. +** +*/ +gceSTATUS +gckOS_GetTicks( + OUT gctUINT32_PTR Time + ) +{ + gcmkHEADER(); + + *Time = jiffies * 1000 / HZ; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_TicksAfter +** +** Compare time values got from gckOS_GetTicks. +** +** INPUT: +** gctUINT32 Time1 +** First time value to be compared. +** +** gctUINT32 Time2 +** Second time value to be compared. +** +** OUTPUT: +** +** gctBOOL_PTR IsAfter +** Pointer to a variable to result. +** +*/ +gceSTATUS +gckOS_TicksAfter( + IN gctUINT32 Time1, + IN gctUINT32 Time2, + OUT gctBOOL_PTR IsAfter + ) +{ + gcmkHEADER(); + + *IsAfter = time_after((unsigned long)Time1, (unsigned long)Time2); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetTime +** +** Get the number of microseconds since the system started. +** +** INPUT: +** +** OUTPUT: +** +** gctUINT64_PTR Time +** Pointer to a variable to get time. +** +*/ +gceSTATUS +gckOS_GetTime( + OUT gctUINT64_PTR Time + ) +{ + gcmkHEADER(); + + *Time = 0; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MemoryBarrier +** +** Make sure the CPU has executed everything up to this point and the data got +** written to the specified pointer. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of memory that needs to be barriered. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_MemoryBarrier( + IN gckOS Os, + IN gctPOINTER Address + ) +{ + gcmkHEADER_ARG("Os=0x%X Address=0x%X", Os, Address); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + +#if gcdNONPAGED_MEMORY_BUFFERABLE \ + && defined (CONFIG_ARM) \ + && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34)) + /* drain write buffer */ + dsb(); + + /* drain outer cache's write buffer? */ +#else + mb(); +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemory +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocatePagedMemory( + IN gckOS Os, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Bytes=%lu", Os, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + + /* Allocate the memory. */ + gcmkONERROR(gckOS_AllocatePagedMemoryEx(Os, gcvFALSE, Bytes, Physical)); + + /* Success. */ + gcmkFOOTER_ARG("*Physical=0x%X", *Physical); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AllocatePagedMemoryEx +** +** Allocate memory from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL Contiguous +** Need contiguous memory or not. +** +** gctSIZE_T Bytes +** Number of bytes to allocate. +** +** OUTPUT: +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocatePagedMemoryEx( + IN gckOS Os, + IN gctBOOL Contiguous, + IN gctSIZE_T Bytes, + OUT gctPHYS_ADDR * Physical + ) +{ + gctINT numPages; + gctINT i; + PLINUX_MDL mdl = gcvNULL; + gctSIZE_T bytes; + gctBOOL locked = gcvFALSE; + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Contiguous=%d Bytes=%lu", Os, Contiguous, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + + bytes = gcmALIGN(Bytes, PAGE_SIZE); + + numPages = GetPageCount(bytes, 0); + + MEMORY_LOCK(Os); + locked = gcvTRUE; + + mdl = _CreateMdl(_GetProcessID()); + if (mdl == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + if (Contiguous) + { + /* Get contiguous pages, and suppress warning (stack dump) from kernel when + we run out of memory. */ + mdl->u.contiguousPages = + alloc_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_NO_KSWAPD, GetOrder(numPages)); + + if (mdl->u.contiguousPages == gcvNULL) + { + mdl->u.contiguousPages = + alloc_pages(GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN | __GFP_NO_KSWAPD, GetOrder(numPages)); + } + } + else + { + mdl->u.nonContiguousPages = _NonContiguousAlloc(numPages); + } + + if (mdl->u.contiguousPages == gcvNULL && mdl->u.nonContiguousPages == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + mdl->dmaHandle = 0; + mdl->addr = 0; + mdl->numPages = numPages; + mdl->pagedMem = 1; + mdl->contiguous = Contiguous; + + for (i = 0; i < mdl->numPages; i++) + { + struct page *page; + + if (mdl->contiguous) + { + page = nth_page(mdl->u.contiguousPages, i); + } + else + { + page = _NonContiguousToPage(mdl->u.nonContiguousPages, i); + } + + SetPageReserved(page); + + if (!PageHighMem(page) && page_to_phys(page)) + { + gcmkVERIFY_OK( + gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL, + (gctPOINTER)page_to_phys(page), + page_address(page), + PAGE_SIZE)); + } + } + + /* Return physical address. */ + *Physical = (gctPHYS_ADDR) mdl; + + /* + * Add this to a global list. + * Will be used by get physical address + * and mapuser pointer functions. + */ + if (!Os->mdlHead) + { + /* Initialize the queue. */ + Os->mdlHead = Os->mdlTail = mdl; + } + else + { + /* Add to tail. */ + mdl->prev = Os->mdlTail; + Os->mdlTail->next = mdl; + Os->mdlTail = mdl; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_ARG("*Physical=0x%X", *Physical); + return gcvSTATUS_OK; + +OnError: + if (mdl != gcvNULL) + { + /* Free the memory. */ + _DestroyMdl(mdl); + } + + if (locked) + { + /* Unlock the memory. */ + MEMORY_UNLOCK(Os); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreePagedMemory +** +** Free memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreePagedMemory( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes + ) +{ + PLINUX_MDL mdl = (PLINUX_MDL) Physical; + gctINT i; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /*addr = mdl->addr;*/ + + MEMORY_LOCK(Os); + + for (i = 0; i < mdl->numPages; i++) + { + if (mdl->contiguous) + { + ClearPageReserved(nth_page(mdl->u.contiguousPages, i)); + } + else + { + ClearPageReserved(_NonContiguousToPage(mdl->u.nonContiguousPages, i)); + } + } + + if (mdl->contiguous) + { + __free_pages(mdl->u.contiguousPages, GetOrder(mdl->numPages)); + } + else + { + _NonContiguousFree(mdl->u.nonContiguousPages, mdl->numPages); + } + + /* Remove the node from global list. */ + if (mdl == Os->mdlHead) + { + if ((Os->mdlHead = mdl->next) == gcvNULL) + { + Os->mdlTail = gcvNULL; + } + } + else + { + mdl->prev->next = mdl->next; + + if (mdl == Os->mdlTail) + { + Os->mdlTail = mdl->prev; + } + else + { + mdl->next->prev = mdl->prev; + } + } + + MEMORY_UNLOCK(Os); + + /* Free the structure... */ + gcmkVERIFY_OK(_DestroyMdl(mdl)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_LockPages +** +** Lock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** gctBOOL Cacheable +** Cache mode of mapping. +** +** OUTPUT: +** +** gctPOINTER * Logical +** Pointer to a variable that receives the address of the mapped +** memory. +** +** gctSIZE_T * PageCount +** Pointer to a variable that receives the number of pages required for +** the page table according to the GPU page size. +*/ +gceSTATUS +gckOS_LockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctBOOL Cacheable, + OUT gctPOINTER * Logical, + OUT gctSIZE_T * PageCount + ) +{ + PLINUX_MDL mdl; + PLINUX_MDL_MAP mdlMap; + gctSTRING addr; + unsigned long start; + unsigned long pfn; + gctINT i; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%lu", Os, Physical, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount != gcvNULL); + + mdl = (PLINUX_MDL) Physical; + + MEMORY_LOCK(Os); + + mdlMap = FindMdlMap(mdl, _GetProcessID()); + + if (mdlMap == gcvNULL) + { + mdlMap = _CreateMdlMap(mdl, _GetProcessID()); + + if (mdlMap == gcvNULL) + { + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + } + + if (mdlMap->vmaAddr == gcvNULL) + { + down_write(¤t->mm->mmap_sem); + + mdlMap->vmaAddr = (gctSTRING)do_mmap_pgoff(gcvNULL, + 0L, + mdl->numPages * PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + 0); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): vmaAddr->0x%X for phys_addr->0x%X", + __FUNCTION__, __LINE__, + (gctUINT32) mdlMap->vmaAddr, + (gctUINT32) mdl + ); + + if (IS_ERR(mdlMap->vmaAddr)) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): do_mmap_pgoff error", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + mdlMap->vma = find_vma(current->mm, (unsigned long)mdlMap->vmaAddr); + + if (mdlMap->vma == gcvNULL) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): find_vma error", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_RESOURCES); + return gcvSTATUS_OUT_OF_RESOURCES; + } + + mdlMap->vma->vm_flags |= VM_RESERVED; +#if !gcdPAGED_MEMORY_CACHEABLE + if (Cacheable == gcvFALSE) + { + /* Make this mapping non-cached. */ + mdlMap->vma->vm_page_prot = gcmkPAGED_MEMROY_PROT(mdlMap->vma->vm_page_prot); + } +#endif + addr = mdl->addr; + + /* Now map all the vmalloc pages to this user address. */ + if (mdl->contiguous) + { + /* map kernel memory to user space.. */ + if (remap_pfn_range(mdlMap->vma, + mdlMap->vma->vm_start, + page_to_pfn(mdl->u.contiguousPages), + mdlMap->vma->vm_end - mdlMap->vma->vm_start, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): unable to mmap ret", + __FUNCTION__, __LINE__ + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + } + else + { + start = mdlMap->vma->vm_start; + + for (i = 0; i < mdl->numPages; i++) + { + pfn = _NonContiguousToPfn(mdl->u.nonContiguousPages, i); + + if (remap_pfn_range(mdlMap->vma, + start, + pfn, + PAGE_SIZE, + mdlMap->vma->vm_page_prot) < 0) + { + up_write(¤t->mm->mmap_sem); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): gctPHYS_ADDR->0x%X Logical->0x%X Unable to map addr->0x%X to start->0x%X", + __FUNCTION__, __LINE__, + (gctUINT32) Physical, + (gctUINT32) *Logical, + (gctUINT32) addr, + (gctUINT32) start + ); + + mdlMap->vmaAddr = gcvNULL; + + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + start += PAGE_SIZE; + addr += PAGE_SIZE; + } + } + + up_write(¤t->mm->mmap_sem); + } + else + { + /* mdlMap->vmaAddr != gcvNULL means current process has already locked this node. */ + MEMORY_UNLOCK(Os); + + gcmkFOOTER_ARG("*status=%d, mdlMap->vmaAddr=%x", gcvSTATUS_MEMORY_LOCKED, mdlMap->vmaAddr); + return gcvSTATUS_MEMORY_LOCKED; + } + + /* Convert pointer to MDL. */ + *Logical = mdlMap->vmaAddr; + + /* Return the page number according to the GPU page size. */ + gcmkASSERT((PAGE_SIZE % 4096) == 0); + gcmkASSERT((PAGE_SIZE / 4096) >= 1); + + *PageCount = mdl->numPages * (PAGE_SIZE / 4096); + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_ARG("*Logical=0x%X *PageCount=%lu", *Logical, *PageCount); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_MapPages +** +** Map paged memory into a page table. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T PageCount +** Number of pages required for the physical address. +** +** gctPOINTER PageTable +** Pointer to the page table to fill in. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_MapPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ) +{ + return gckOS_MapPagesEx(Os, + gcvCORE_MAJOR, + Physical, + PageCount, + PageTable); +} + +gceSTATUS +gckOS_MapPagesEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T PageCount, + IN gctPOINTER PageTable + ) +{ + gceSTATUS status = gcvSTATUS_OK; + PLINUX_MDL mdl; + gctUINT32* table; + gctUINT32 offset; +#if gcdNONPAGED_MEMORY_CACHEABLE + gckMMU mmu; + PLINUX_MDL mmuMdl; + gctUINT32 bytes; + gctPHYS_ADDR pageTablePhysical; +#endif + + gcmkHEADER_ARG("Os=0x%X Core=%d Physical=0x%X PageCount=%u PageTable=0x%X", + Os, Core, Physical, PageCount, PageTable); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(PageCount > 0); + gcmkVERIFY_ARGUMENT(PageTable != gcvNULL); + + /* Convert pointer to MDL. */ + mdl = (PLINUX_MDL)Physical; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): Physical->0x%X PageCount->0x%X PagedMemory->?%d", + __FUNCTION__, __LINE__, + (gctUINT32) Physical, + (gctUINT32) PageCount, + mdl->pagedMem + ); + + MEMORY_LOCK(Os); + + table = (gctUINT32 *)PageTable; +#if gcdNONPAGED_MEMORY_CACHEABLE + mmu = Os->device->kernels[Core]->mmu; + bytes = PageCount * sizeof(*table); + mmuMdl = (PLINUX_MDL)mmu->pageTablePhysical; +#endif + + /* Get all the physical addresses and store them in the page table. */ + + offset = 0; + + if (mdl->pagedMem) + { + /* Try to get the user pages so DMA can happen. */ + while (PageCount-- > 0) + { +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + if (mdl->contiguous) + { + gcmkONERROR( + gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, + page_to_phys(nth_page(mdl->u.contiguousPages, offset)), + table)); + } + else + { + gcmkONERROR( + gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, + _NonContiguousToPhys(mdl->u.nonContiguousPages, offset), + table)); + } + } + else +#endif + { + if (mdl->contiguous) + { + gcmkONERROR( + gckMMU_SetPage(Os->device->kernels[Core]->mmu, + page_to_phys(nth_page(mdl->u.contiguousPages, offset)), + table)); + } + else + { + gcmkONERROR( + gckMMU_SetPage(Os->device->kernels[Core]->mmu, + _NonContiguousToPhys(mdl->u.nonContiguousPages, offset), + table)); + } + } + + table++; + offset += 1; + } + } + else + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): we should not get this call for Non Paged Memory!", + __FUNCTION__, __LINE__ + ); + + while (PageCount-- > 0) + { +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + gcmkONERROR( + gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, + page_to_phys(nth_page(mdl->u.contiguousPages, offset)), + table)); + } + else +#endif + { + gcmkONERROR( + gckMMU_SetPage(Os->device->kernels[Core]->mmu, + page_to_phys(nth_page(mdl->u.contiguousPages, offset)), + table)); + } + table++; + offset += 1; + } + } + +#if gcdNONPAGED_MEMORY_CACHEABLE + /* Get physical address of pageTable */ + pageTablePhysical = (gctPHYS_ADDR)(mmuMdl->dmaHandle + + ((gctUINT32 *)PageTable - mmu->pageTableLogical)); + + /* Flush the mmu page table cache. */ + gcmkONERROR(gckOS_CacheClean( + Os, + _GetProcessID(), + gcvNULL, + pageTablePhysical, + PageTable, + bytes + )); +#endif + +OnError: + + MEMORY_UNLOCK(Os); + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_UnlockPages +** +** Unlock memory allocated from the paged pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** gctPOINTER Logical +** Address of the mapped memory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnlockPages( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctSIZE_T Bytes, + IN gctPOINTER Logical + ) +{ + PLINUX_MDL_MAP mdlMap; + PLINUX_MDL mdl = (PLINUX_MDL)Physical; + struct task_struct * task; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Bytes=%u Logical=0x%X", + Os, Physical, Bytes, Logical); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Make sure there is already a mapping...*/ + gcmkVERIFY_ARGUMENT(mdl->u.nonContiguousPages != gcvNULL + || mdl->u.contiguousPages != gcvNULL); + + MEMORY_LOCK(Os); + + mdlMap = mdl->maps; + + while (mdlMap != gcvNULL) + { + if ((mdlMap->vmaAddr != gcvNULL) && (_GetProcessID() == mdlMap->pid)) + { + /* Get the current pointer for the task with stored pid. */ + task = FIND_TASK_BY_PID(mdlMap->pid); + + if (task != gcvNULL && task->mm != gcvNULL) + { + down_write(&task->mm->mmap_sem); + do_munmap(task->mm, (unsigned long)mdlMap->vmaAddr, mdl->numPages * PAGE_SIZE); + up_write(&task->mm->mmap_sem); + } + + mdlMap->vmaAddr = gcvNULL; + } + + mdlMap = mdlMap->next; + } + + MEMORY_UNLOCK(Os); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + + +/******************************************************************************* +** +** gckOS_AllocateContiguous +** +** Allocate memory from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL InUserSpace +** gcvTRUE if the pages need to be mapped into user space. +** +** gctSIZE_T * Bytes +** Pointer to the number of bytes to allocate. +** +** OUTPUT: +** +** gctSIZE_T * Bytes +** Pointer to a variable that receives the number of bytes allocated. +** +** gctPHYS_ADDR * Physical +** Pointer to a variable that receives the physical address of the +** memory allocation. +** +** gctPOINTER * Logical +** Pointer to a variable that receives the logical address of the +** memory allocation. +*/ +gceSTATUS +gckOS_AllocateContiguous( + IN gckOS Os, + IN gctBOOL InUserSpace, + IN OUT gctSIZE_T * Bytes, + OUT gctPHYS_ADDR * Physical, + OUT gctPOINTER * Logical + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X InUserSpace=%d *Bytes=%lu", + Os, InUserSpace, gcmOPT_VALUE(Bytes)); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Bytes != gcvNULL); + gcmkVERIFY_ARGUMENT(*Bytes > 0); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + + /* Same as non-paged memory for now. */ + gcmkONERROR(gckOS_AllocateNonPagedMemory(Os, + InUserSpace, + Bytes, + Physical, + Logical)); + + /* Success. */ + gcmkFOOTER_ARG("*Bytes=%lu *Physical=0x%X *Logical=0x%X", + *Bytes, *Physical, *Logical); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_FreeContiguous +** +** Free memory allocated from the contiguous pool. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPHYS_ADDR Physical +** Physical address of the allocation. +** +** gctPOINTER Logical +** Logicval address of the allocation. +** +** gctSIZE_T Bytes +** Number of bytes of the allocation. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_FreeContiguous( + IN gckOS Os, + IN gctPHYS_ADDR Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Physical=0x%X Logical=0x%X Bytes=%lu", + Os, Physical, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Physical != gcvNULL); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + /* Same of non-paged memory for now. */ + gcmkONERROR(gckOS_FreeNonPagedMemory(Os, Bytes, Physical, Logical)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +#if gcdENABLE_VG +/****************************************************************************** +** +** gckOS_GetKernelLogical +** +** Return the kernel logical pointer that corresponods to the specified +** hardware address. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 Address +** Hardware physical address. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the pointer in kernel address space. +*/ +gceSTATUS +gckOS_GetKernelLogical( + IN gckOS Os, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + return gckOS_GetKernelLogicalEx(Os, gcvCORE_MAJOR, Address, KernelPointer); +} + +gceSTATUS +gckOS_GetKernelLogicalEx( + IN gckOS Os, + IN gceCORE Core, + IN gctUINT32 Address, + OUT gctPOINTER * KernelPointer + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Core=%d Address=0x%08x", Os, Core, Address); + + do + { + gckGALDEVICE device; + gckKERNEL kernel; + gcePOOL pool; + gctUINT32 offset; + gctPOINTER logical; + + /* Extract the pointer to the gckGALDEVICE class. */ + device = (gckGALDEVICE) Os->device; + + /* Kernel shortcut. */ + kernel = device->kernels[Core]; +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + gcmkERR_BREAK(gckVGHARDWARE_SplitMemory( + kernel->vg->hardware, Address, &pool, &offset + )); + } + else +#endif + { + /* Split the memory address into a pool type and offset. */ + gcmkERR_BREAK(gckHARDWARE_SplitMemory( + kernel->hardware, Address, &pool, &offset + )); + } + + /* Dispatch on pool. */ + switch (pool) + { + case gcvPOOL_LOCAL_INTERNAL: + /* Internal memory. */ + logical = device->internalLogical; + break; + + case gcvPOOL_LOCAL_EXTERNAL: + /* External memory. */ + logical = device->externalLogical; + break; + + case gcvPOOL_SYSTEM: + /* System memory. */ + logical = device->contiguousBase; + break; + + default: + /* Invalid memory pool. */ + gcmkFOOTER(); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Build logical address of specified address. */ + * KernelPointer = ((gctUINT8_PTR) logical) + offset; + + /* Success. */ + gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer); + return gcvSTATUS_OK; + } + while (gcvFALSE); + + /* Return status. */ + gcmkFOOTER(); + return status; +} +#endif + +/******************************************************************************* +** +** gckOS_MapUserPointer +** +** Map a pointer from the user process into the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be mapped. +** +** gctSIZE_T Size +** Number of bytes that need to be mapped. +** +** OUTPUT: +** +** gctPOINTER * KernelPointer +** Pointer to a variable receiving the mapped pointer in kernel address +** space. +*/ +gceSTATUS +gckOS_MapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + OUT gctPOINTER * KernelPointer + ) +{ + gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu", Os, Pointer, Size); + +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL +{ + gctPOINTER buf = gcvNULL; + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + buf = kmalloc(Size, GFP_KERNEL | __GFP_NOWARN); + if (buf == gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): Failed to allocate memory.", + __FUNCTION__, __LINE__ + ); + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + len = copy_from_user(buf, Pointer, Size); + if (len != 0) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): Failed to copy data from user.", + __FUNCTION__, __LINE__ + ); + + if (buf != gcvNULL) + { + kfree(buf); + } + + gcmkFOOTER_ARG("*status=%d", gcvSTATUS_GENERIC_IO); + return gcvSTATUS_GENERIC_IO; + } + + *KernelPointer = buf; +} +#else + *KernelPointer = Pointer; +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + gcmkFOOTER_ARG("*KernelPointer=0x%X", *KernelPointer); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_UnmapUserPointer +** +** Unmap a user process pointer from the kernel address space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Pointer +** Pointer in user process space that needs to be unmapped. +** +** gctSIZE_T Size +** Number of bytes that need to be unmapped. +** +** gctPOINTER KernelPointer +** Pointer in kernel address space that needs to be unmapped. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserPointer( + IN gckOS Os, + IN gctPOINTER Pointer, + IN gctSIZE_T Size, + IN gctPOINTER KernelPointer + ) +{ + gcmkHEADER_ARG("Os=0x%X Pointer=0x%X Size=%lu KernelPointer=0x%X", + Os, Pointer, Size, KernelPointer); + +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL +{ + gctUINT32 len; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + + len = copy_to_user(Pointer, KernelPointer, Size); + + kfree(KernelPointer); + + if (len != 0) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): Failed to copy data to user.", + __FUNCTION__, __LINE__ + ); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_GENERIC_IO); + return gcvSTATUS_GENERIC_IO; + } +} +#endif /* NO_USER_DIRECT_ACCESS_FROM_KERNEL */ + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_QueryNeedCopy +** +** Query whether the memory can be accessed or mapped directly or it has to be +** copied. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctUINT32 ProcessID +** Process ID of the current process. +** +** OUTPUT: +** +** gctBOOL_PTR NeedCopy +** Pointer to a boolean receiving gcvTRUE if the memory needs a copy or +** gcvFALSE if the memory can be accessed or mapped dircetly. +*/ +gceSTATUS +gckOS_QueryNeedCopy( + IN gckOS Os, + IN gctUINT32 ProcessID, + OUT gctBOOL_PTR NeedCopy + ) +{ + gcmkHEADER_ARG("Os=0x%X ProcessID=%d", Os, ProcessID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(NeedCopy != gcvNULL); + +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + /* We need to copy data. */ + *NeedCopy = gcvTRUE; +#else + /* No need to copy data. */ + *NeedCopy = gcvFALSE; +#endif + + /* Success. */ + gcmkFOOTER_ARG("*NeedCopy=%d", *NeedCopy); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_CopyFromUserData +** +** Copy data from user to kernel memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER KernelPointer +** Pointer to kernel memory. +** +** gctPOINTER Pointer +** Pointer to user memory. +** +** gctSIZE_T Size +** Number of bytes to copy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_CopyFromUserData( + IN gckOS Os, + IN gctPOINTER KernelPointer, + IN gctPOINTER Pointer, + IN gctSIZE_T Size + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu", + Os, KernelPointer, Pointer, Size); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + + /* Copy data from user. */ + if (copy_from_user(KernelPointer, Pointer, Size) != 0) + { + /* Could not copy all the bytes. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_CopyToUserData +** +** Copy data from kernel to user memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER KernelPointer +** Pointer to kernel memory. +** +** gctPOINTER Pointer +** Pointer to user memory. +** +** gctSIZE_T Size +** Number of bytes to copy. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_CopyToUserData( + IN gckOS Os, + IN gctPOINTER KernelPointer, + IN gctPOINTER Pointer, + IN gctSIZE_T Size + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X KernelPointer=0x%X Pointer=0x%X Size=%lu", + Os, KernelPointer, Pointer, Size); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(KernelPointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Pointer != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + + /* Copy data to user. */ + if (copy_to_user(Pointer, KernelPointer, Size) != 0) + { + /* Could not copy all the bytes. */ + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WriteMemory +** +** Write data to a memory. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctPOINTER Address +** Address of the memory to write to. +** +** gctUINT32 Data +** Data for register. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WriteMemory( + IN gckOS Os, + IN gctPOINTER Address, + IN gctUINT32 Data + ) +{ + gceSTATUS status; + gcmkHEADER_ARG("Os=0x%X Address=0x%X Data=%u", Os, Address, Data); + + /* Verify the arguments. */ + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + /* Write memory. */ +#if NO_USER_DIRECT_ACCESS_FROM_KERNEL + if (access_ok(VERIFY_WRITE, Address, 4)) + { + /* User address. */ + if(put_user(Data, (gctUINT32*)Address)) + { + gcmkONERROR(gcvSTATUS_INVALID_ADDRESS); + } + } + else +#endif + { + /* Kernel address. */ + *(gctUINT32 *)Address = Data; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_MapUserMemory +** +** Lock down a user buffer and return an DMA'able address to be used by the +** hardware to access it. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to lock down. +** +** gctSIZE_T Size +** Size in bytes of the memory to lock down. +** +** OUTPUT: +** +** gctPOINTER * Info +** Pointer to variable receiving the information record required by +** gckOS_UnmapUserMemory. +** +** gctUINT32_PTR Address +** Pointer to a variable that will receive the address DMA'able by the +** hardware. +*/ +gceSTATUS +gckOS_MapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ) +{ + return gckOS_MapUserMemoryEx(Os, gcvCORE_MAJOR, Memory, Size, Info, Address); +} + +gceSTATUS +gckOS_MapUserMemoryEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + OUT gctPOINTER * Info, + OUT gctUINT32_PTR Address + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x Core=%d Memory=0x%x Size=%lu", Os, Core, Memory, Size); + +#if gcdSECURE_USER + gcmkONERROR(gckOS_AddMapping(Os, *Address, Memory, Size)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +#else +{ + gctSIZE_T pageCount, i, j; + gctUINT32_PTR pageTable; + gctUINT32 address = 0, physical = ~0U; + gctUINT32 start, end, memory; + gctINT result = 0; + + gcsPageInfo_PTR info = gcvNULL; + struct page **pages = gcvNULL; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + gcmkVERIFY_ARGUMENT(Address != gcvNULL); + + do + { + memory = (gctUINT32) Memory; + + /* Get the number of required pages. */ + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): pageCount: %d.", + __FUNCTION__, __LINE__, + pageCount + ); + + /* Invalid argument. */ + if (pageCount == 0) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Overflow. */ + if ((memory + Size) < memory) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + MEMORY_MAP_LOCK(Os); + + /* Allocate the Info struct. */ + info = (gcsPageInfo_PTR)kmalloc(sizeof(gcsPageInfo), GFP_KERNEL | __GFP_NOWARN); + + if (info == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Allocate the array of page addresses. */ + pages = (struct page **)kmalloc(pageCount * sizeof(struct page *), GFP_KERNEL | __GFP_NOWARN); + + if (pages == gcvNULL) + { + status = gcvSTATUS_OUT_OF_MEMORY; + break; + } + + /* Get the user pages. */ + down_read(¤t->mm->mmap_sem); + result = get_user_pages(current, + current->mm, + memory & PAGE_MASK, + pageCount, + 1, + 0, + pages, + gcvNULL + ); + up_read(¤t->mm->mmap_sem); + + if (result <=0 || result < pageCount) + { + struct vm_area_struct *vma; + + /* Free the page table. */ + if (pages != gcvNULL) + { + /* Release the pages if any. */ + if (result > 0) + { + for (i = 0; i < result; i++) + { + if (pages[i] == gcvNULL) + { + break; + } + + page_cache_release(pages[i]); + } + } + + kfree(pages); + pages = gcvNULL; + } + + vma = find_vma(current->mm, memory); + + if (vma && (vma->vm_flags & VM_PFNMAP) ) + { + pte_t * pte; + spinlock_t * ptl; + unsigned long pfn; + + pgd_t * pgd = pgd_offset(current->mm, memory); + pud_t * pud = pud_offset(pgd, memory); + if (pud) + { + pmd_t * pmd = pmd_offset(pud, memory); + pte = pte_offset_map_lock(current->mm, pmd, memory, &ptl); + if (!pte) + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + else + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + + pfn = pte_pfn(*pte); + + physical = (pfn << PAGE_SHIFT) | (memory & ~PAGE_MASK); + + pte_unmap_unlock(pte, ptl); + + if ((Os->device->kernels[Core]->hardware->mmuVersion == 0) + && !((physical - Os->device->baseAddress) & 0x80000000)) + { + /* Release page info struct. */ + if (info != gcvNULL) + { + /* Free the page info struct. */ + kfree(info); + } + + MEMORY_MAP_UNLOCK(Os); + + *Address = physical - Os->device->baseAddress; + *Info = gcvNULL; + + gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", + *Info, *Address); + + return gcvSTATUS_OK; + } + } + else + { + gcmkONERROR(gcvSTATUS_OUT_OF_RESOURCES); + } + } + + if (pages) + { + for (i = 0; i < pageCount; i++) + { + /* Flush(clean) the data cache. */ + gcmkONERROR(gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL, + (gctPOINTER)page_to_phys(pages[i]), + (gctPOINTER)(memory & PAGE_MASK) + i*PAGE_SIZE, + PAGE_SIZE)); + } + } + else + { + /* Flush(clean) the data cache. */ + gcmkONERROR(gckOS_CacheFlush(Os, _GetProcessID(), gcvNULL, + (gctPOINTER)(physical & PAGE_MASK), + (gctPOINTER)(memory & PAGE_MASK), + PAGE_SIZE * pageCount)); + + } + +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + /* Allocate pages inside the page table. */ + gcmkERR_BREAK(gckVGMMU_AllocatePages(Os->device->kernels[Core]->vg->mmu, + pageCount * (PAGE_SIZE/4096), + (gctPOINTER *) &pageTable, + &address)); + } + else +#endif + { + /* Allocate pages inside the page table. */ + gcmkERR_BREAK(gckMMU_AllocatePages(Os->device->kernels[Core]->mmu, + pageCount * (PAGE_SIZE/4096), + (gctPOINTER *) &pageTable, + &address)); + } + /* Fill the page table. */ + for (i = 0; i < pageCount; i++) + { + gctUINT32 phys; + gctUINT32_PTR tab = pageTable + i * (PAGE_SIZE/4096); + + if (pages) + { + phys = page_to_phys(pages[i]); + } + else + { + phys = (physical & PAGE_MASK) + i * PAGE_SIZE; + } + +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + /* Get the physical address from page struct. */ + gcmkONERROR( + gckVGMMU_SetPage(Os->device->kernels[Core]->vg->mmu, + phys, + tab)); + } + else +#endif + { + /* Get the physical address from page struct. */ + gcmkONERROR( + gckMMU_SetPage(Os->device->kernels[Core]->mmu, + phys, + tab)); + } + + for (j = 1; j < (PAGE_SIZE/4096); j++) + { + pageTable[i * (PAGE_SIZE/4096) + j] = pageTable[i * (PAGE_SIZE/4096)] + 4096 * j; + } + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): pageTable[%d]: 0x%X 0x%X.", + __FUNCTION__, __LINE__, + i, phys, pageTable[i]); + } + +#if gcdENABLE_VG + if (Core != gcvCORE_VG) +#endif + { + gcmkONERROR(gckMMU_Flush(Os->device->kernels[Core]->mmu)); + } + + /* Save pointer to page table. */ + info->pageTable = pageTable; + info->pages = pages; + + *Info = (gctPOINTER) info; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): info->pages: 0x%X, info->pageTable: 0x%X, info: 0x%X.", + __FUNCTION__, __LINE__, + info->pages, + info->pageTable, + info + ); + + /* Return address. */ + *Address = address + (memory & ~PAGE_MASK); + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): Address: 0x%X.", + __FUNCTION__, __LINE__, + *Address + ); + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + +OnError: + + if (gcmIS_ERROR(status)) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): error occured: %d.", + __FUNCTION__, __LINE__, + status + ); + + /* Release page array. */ + if (result > 0 && pages != gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): error: page table is freed.", + __FUNCTION__, __LINE__ + ); + + for (i = 0; i < result; i++) + { + if (pages[i] == gcvNULL) + { + break; + } + page_cache_release(pages[i]); + } + } + + if (info!= gcvNULL && pages != gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): error: pages is freed.", + __FUNCTION__, __LINE__ + ); + + /* Free the page table. */ + kfree(pages); + info->pages = gcvNULL; + } + + /* Release page info struct. */ + if (info != gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): error: info is freed.", + __FUNCTION__, __LINE__ + ); + + /* Free the page info struct. */ + kfree(info); + *Info = gcvNULL; + } + } + + MEMORY_MAP_UNLOCK(Os); + + /* Return the status. */ + if (gcmIS_SUCCESS(status)) + { + gcmkFOOTER_ARG("*Info=0x%X *Address=0x%08x", *Info, *Address); + } + else + { + gcmkFOOTER(); + } + + return status; +} +#endif +} + +/******************************************************************************* +** +** gckOS_UnmapUserMemory +** +** Unlock a user buffer and that was previously locked down by +** gckOS_MapUserMemory. +** +** INPUT: +** +** gctPOINTER Memory +** Pointer to memory to unlock. +** +** gctSIZE_T Size +** Size in bytes of the memory to unlock. +** +** gctPOINTER Info +** Information record returned by gckOS_MapUserMemory. +** +** gctUINT32_PTR Address +** The address returned by gckOS_MapUserMemory. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UnmapUserMemory( + IN gckOS Os, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ) +{ + return gckOS_UnmapUserMemoryEx(Os, gcvCORE_MAJOR, Memory, Size, Info, Address); +} + +gceSTATUS +gckOS_UnmapUserMemoryEx( + IN gckOS Os, + IN gceCORE Core, + IN gctPOINTER Memory, + IN gctSIZE_T Size, + IN gctPOINTER Info, + IN gctUINT32 Address + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Core=%d Memory=0x%X Size=%lu Info=0x%X Address0x%08x", + Os, Core, Memory, Size, Info, Address); + +#if gcdSECURE_USER + gcmkONERROR(gckOS_RemoveMapping(Os, Memory, Size)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +#else +{ + gctUINT32 memory, start, end; + gcsPageInfo_PTR info; + gctSIZE_T pageCount, i; + struct page **pages; + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Size > 0); + gcmkVERIFY_ARGUMENT(Info != gcvNULL); + + do + { + /*gctUINT32 physical = ~0U;*/ + + info = (gcsPageInfo_PTR) Info; + + pages = info->pages; + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): info=0x%X, pages=0x%X.", + __FUNCTION__, __LINE__, + info, pages + ); + + /* Invalid page array. */ + if (pages == gcvNULL) + { + if (info->pageTable == gcvNULL) + { + kfree(info); + + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + else + { + /*physical = (*info->pageTable) & PAGE_MASK;*/ + } + } + + memory = (gctUINT32) Memory; + end = (memory + Size + PAGE_SIZE - 1) >> PAGE_SHIFT; + start = memory >> PAGE_SHIFT; + pageCount = end - start; + + /* Overflow. */ + if ((memory + Size) < memory) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + /* Invalid argument. */ + if (pageCount == 0) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_INVALID_ARGUMENT); + return gcvSTATUS_INVALID_ARGUMENT; + } + + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): memory: 0x%X, pageCount: %d, pageTable: 0x%X.", + __FUNCTION__, __LINE__, + memory, pageCount, info->pageTable + ); + + MEMORY_MAP_LOCK(Os); + +#if gcdENABLE_VG + if (Core == gcvCORE_VG) + { + /* Free the pages from the MMU. */ + gcmkERR_BREAK(gckVGMMU_FreePages(Os->device->kernels[Core]->vg->mmu, + info->pageTable, + pageCount * (PAGE_SIZE/4096) + )); + } + else +#endif + { + /* Free the pages from the MMU. */ + gcmkERR_BREAK(gckMMU_FreePages(Os->device->kernels[Core]->mmu, + info->pageTable, + pageCount * (PAGE_SIZE/4096) + )); + } + + /* Release the page cache. */ + if (pages) + { + for (i = 0; i < pageCount; i++) + { + gcmkTRACE_ZONE( + gcvLEVEL_INFO, gcvZONE_OS, + "%s(%d): pages[%d]: 0x%X.", + __FUNCTION__, __LINE__, + i, pages[i] + ); + + if (!PageReserved(pages[i])) + { + SetPageDirty(pages[i]); + } + + page_cache_release(pages[i]); + } + } + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + if (info != gcvNULL) + { + /* Free the page array. */ + if (info->pages != gcvNULL) + { + kfree(info->pages); + } + + kfree(info); + } + + MEMORY_MAP_UNLOCK(Os); + + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif +} + +/******************************************************************************* +** +** gckOS_GetBaseAddress +** +** Get the base address for the physical memory. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctUINT32_PTR BaseAddress +** Pointer to a variable that will receive the base address. +*/ +gceSTATUS +gckOS_GetBaseAddress( + IN gckOS Os, + OUT gctUINT32_PTR BaseAddress + ) +{ + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(BaseAddress != gcvNULL); + + /* Return base address. */ + *BaseAddress = Os->device->baseAddress; + + /* Success. */ + gcmkFOOTER_ARG("*BaseAddress=0x%08x", *BaseAddress); + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_SuspendInterrupt( + IN gckOS Os + ) +{ + return gckOS_SuspendInterruptEx(Os, gcvCORE_MAJOR); +} + +gceSTATUS +gckOS_SuspendInterruptEx( + IN gckOS Os, + IN gceCORE Core + ) +{ + gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + disable_irq(Os->device->irqLines[Core]); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ResumeInterrupt( + IN gckOS Os + ) +{ + return gckOS_ResumeInterruptEx(Os, gcvCORE_MAJOR); +} + +gceSTATUS +gckOS_ResumeInterruptEx( + IN gckOS Os, + IN gceCORE Core + ) +{ + gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + enable_irq(Os->device->irqLines[Core]); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_MemCopy( + IN gctPOINTER Destination, + IN gctCONST_POINTER Source, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Destination=0x%X Source=0x%X Bytes=%lu", + Destination, Source, Bytes); + + gcmkVERIFY_ARGUMENT(Destination != gcvNULL); + gcmkVERIFY_ARGUMENT(Source != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memcpy(Destination, Source, Bytes); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_ZeroMemory( + IN gctPOINTER Memory, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Memory=0x%X Bytes=%lu", Memory, Bytes); + + gcmkVERIFY_ARGUMENT(Memory != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + + memset(Memory, 0, Bytes); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +********************************* Cache Control ******************************** +*******************************************************************************/ + +#if !gcdCACHE_FUNCTION_UNIMPLEMENTED && defined(CONFIG_OUTER_CACHE) +static inline gceSTATUS +outer_func( + gceCACHEOPERATION Type, + unsigned long Start, + unsigned long End + ) +{ + switch (Type) + { + case gcvCACHE_CLEAN: + outer_clean_range(Start, End); + break; + case gcvCACHE_INVALIDATE: + outer_inv_range(Start, End); + break; + case gcvCACHE_FLUSH: + outer_flush_range(Start, End); + break; + default: + return gcvSTATUS_INVALID_ARGUMENT; + break; + } + return gcvSTATUS_OK; +} + +#if gcdENABLE_OUTER_CACHE_PATCH +/******************************************************************************* +** _HandleOuterCache +** +** Handle the outer cache for the specified addresses. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctUINT32 ProcessID +** Process ID Logical belongs. +** +** gctPHYS_ADDR Handle +** Physical address handle. If gcvNULL it is video memory. +** +** gctPOINTER Physical +** Physical address to flush. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +** +** gceOUTERCACHE_OPERATION Type +** Operation need to be execute. +*/ +static gceSTATUS +_HandleOuterCache( + IN gckOS Os, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes, + IN gceCACHEOPERATION Type + ) +{ + gceSTATUS status; + gctUINT32 i, pageNum; + unsigned long paddr; + gctPOINTER vaddr; + + gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", + Os, ProcessID, Handle, Logical, Bytes); + + if (Physical != gcvNULL) + { + /* Non paged memory or gcvPOOL_USER surface */ + paddr = (unsigned long) Physical; + gcmkONERROR(outer_func(Type, paddr, paddr + Bytes)); + } + else if ((Handle == gcvNULL) + || (Handle != gcvNULL && ((PLINUX_MDL)Handle)->contiguous) + ) + { + /* Video Memory or contiguous virtual memory */ + gcmkONERROR(gckOS_GetPhysicalAddress(Os, Logical, (gctUINT32*)&paddr)); + gcmkONERROR(outer_func(Type, paddr, paddr + Bytes)); + } + else + { + /* Non contiguous virtual memory */ + vaddr = (gctPOINTER)gcmALIGN_BASE((gctUINT32)Logical, PAGE_SIZE); + pageNum = GetPageCount(Bytes, 0); + + for (i = 0; i < pageNum; i += 1) + { + gcmkONERROR(_ConvertLogical2Physical( + Os, + vaddr + PAGE_SIZE * i, + ProcessID, + (PLINUX_MDL)Handle, + (gctUINT32*)&paddr + )); + + gcmkONERROR(outer_func(Type, paddr, paddr + PAGE_SIZE)); + } + } + + mb(); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} +#endif +#endif + +/******************************************************************************* +** gckOS_CacheClean +** +** Clean the cache for the specified addresses. The GPU is going to need the +** data. If the system is allocating memory as non-cachable, this function can +** be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctUINT32 ProcessID +** Process ID Logical belongs. +** +** gctPHYS_ADDR Handle +** Physical address handle. If gcvNULL it is video memory. +** +** gctPOINTER Physical +** Physical address to flush. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheClean( + IN gckOS Os, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", + Os, ProcessID, Handle, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + +#if !gcdCACHE_FUNCTION_UNIMPLEMENTED +#ifdef CONFIG_ARM + + /* Inner cache. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) + dmac_map_area(Logical, Bytes, DMA_TO_DEVICE); +# else + dmac_clean_range(Logical, Logical + Bytes); +# endif + +#if defined(CONFIG_OUTER_CACHE) + /* Outer cache. */ +#if gcdENABLE_OUTER_CACHE_PATCH + _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_CLEAN); +#else + outer_clean_range((unsigned long) Handle, (unsigned long) Handle + Bytes); +#endif +#endif + +#elif defined(CONFIG_MIPS) + + dma_cache_wback((unsigned long) Logical, Bytes); + +#else + dma_sync_single_for_device( + gcvNULL, + Physical, + Bytes, + DMA_TO_DEVICE); +#endif +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** gckOS_CacheInvalidate +** +** Invalidate the cache for the specified addresses. The GPU is going to need +** data. If the system is allocating memory as non-cachable, this function can +** be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctUINT32 ProcessID +** Process ID Logical belongs. +** +** gctPHYS_ADDR Handle +** Physical address handle. If gcvNULL it is video memory. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheInvalidate( + IN gckOS Os, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", + Os, ProcessID, Handle, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + +#if !gcdCACHE_FUNCTION_UNIMPLEMENTED +#ifdef CONFIG_ARM + + /* Inner cache. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) + dmac_map_area(Logical, Bytes, DMA_FROM_DEVICE); +# else + dmac_inv_range(Logical, Logical + Bytes); +# endif + +#if defined(CONFIG_OUTER_CACHE) + /* Outer cache. */ +#if gcdENABLE_OUTER_CACHE_PATCH + _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_INVALIDATE); +#else + outer_inv_range((unsigned long) Handle, (unsigned long) Handle + Bytes); +#endif +#endif + +#elif defined(CONFIG_MIPS) + dma_cache_inv((unsigned long) Logical, Bytes); +#else + dma_sync_single_for_device( + gcvNULL, + Physical, + Bytes, + DMA_FROM_DEVICE); +#endif +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** gckOS_CacheFlush +** +** Clean the cache for the specified addresses and invalidate the lines as +** well. The GPU is going to need and modify the data. If the system is +** allocating memory as non-cachable, this function can be ignored. +** +** ARGUMENTS: +** +** gckOS Os +** Pointer to gckOS object. +** +** gctUINT32 ProcessID +** Process ID Logical belongs. +** +** gctPHYS_ADDR Handle +** Physical address handle. If gcvNULL it is video memory. +** +** gctPOINTER Logical +** Logical address to flush. +** +** gctSIZE_T Bytes +** Size of the address range in bytes to flush. +*/ +gceSTATUS +gckOS_CacheFlush( + IN gckOS Os, + IN gctUINT32 ProcessID, + IN gctPHYS_ADDR Handle, + IN gctPOINTER Physical, + IN gctPOINTER Logical, + IN gctSIZE_T Bytes + ) +{ + gcmkHEADER_ARG("Os=0x%X ProcessID=%d Handle=0x%X Logical=0x%X Bytes=%lu", + Os, ProcessID, Handle, Logical, Bytes); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Logical != gcvNULL); + gcmkVERIFY_ARGUMENT(Bytes > 0); + +#if !gcdCACHE_FUNCTION_UNIMPLEMENTED +#ifdef CONFIG_ARM + /* Inner cache. */ + dmac_flush_range(Logical, Logical + Bytes); + +#if defined(CONFIG_OUTER_CACHE) + /* Outer cache. */ +#if gcdENABLE_OUTER_CACHE_PATCH + _HandleOuterCache(Os, ProcessID, Handle, Physical, Logical, Bytes, gcvCACHE_FLUSH); +#else + outer_flush_range((unsigned long) Handle, (unsigned long) Handle + Bytes); +#endif +#endif + +#elif defined(CONFIG_MIPS) + dma_cache_wback_inv((unsigned long) Logical, Bytes); +#else + dma_sync_single_for_device( + gcvNULL, + Physical, + Bytes, + DMA_BIDIRECTIONAL); +#endif +#endif + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +********************************* Broadcasting ********************************* +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_Broadcast +** +** System hook for broadcast events from the kernel driver. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gceBROADCAST Reason +** Reason for the broadcast. Can be one of the following values: +** +** gcvBROADCAST_GPU_IDLE +** Broadcasted when the kernel driver thinks the GPU might be +** idle. This can be used to handle power management. +** +** gcvBROADCAST_GPU_COMMIT +** Broadcasted when any client process commits a command +** buffer. This can be used to handle power management. +** +** gcvBROADCAST_GPU_STUCK +** Broadcasted when the kernel driver hits the timeout waiting +** for the GPU. +** +** gcvBROADCAST_FIRST_PROCESS +** First process is trying to connect to the kernel. +** +** gcvBROADCAST_LAST_PROCESS +** Last process has detached from the kernel. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Broadcast( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gceBROADCAST Reason + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%X Hardware=0x%X Reason=%d", Os, Hardware, Reason); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_OBJECT(Hardware, gcvOBJ_HARDWARE); + + switch (Reason) + { + case gcvBROADCAST_FIRST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "First process has attached"); + break; + + case gcvBROADCAST_LAST_PROCESS: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "Last process has detached"); + + /* Put GPU OFF. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_OFF_BROADCAST)); + break; + + case gcvBROADCAST_GPU_IDLE: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "GPU idle."); + + /* Put GPU IDLE. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, + gcvPOWER_IDLE_BROADCAST)); + + /* Add idle process DB. */ + gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel, + 1, + gcvDB_IDLE, + gcvNULL, gcvNULL, 0)); + break; + + case gcvBROADCAST_GPU_COMMIT: + gcmkTRACE_ZONE(gcvLEVEL_INFO, gcvZONE_OS, "COMMIT has arrived."); + + /* Add busy process DB. */ + gcmkONERROR(gckKERNEL_AddProcessDB(Hardware->kernel, + 0, + gcvDB_IDLE, + gcvNULL, gcvNULL, 0)); + + /* Put GPU ON. */ + gcmkONERROR( + gckHARDWARE_SetPowerManagementState(Hardware, gcvPOWER_ON_AUTO)); + break; + + case gcvBROADCAST_GPU_STUCK: + gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_GPU_STUCK\n"); + gcmkONERROR(_DumpGPUState(Os, gcvCORE_MAJOR)); + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + + case gcvBROADCAST_AXI_BUS_ERROR: + gcmkTRACE_N(gcvLEVEL_ERROR, 0, "gcvBROADCAST_AXI_BUS_ERROR\n"); + gcmkONERROR(_DumpGPUState(Os, gcvCORE_MAJOR)); + gcmkONERROR(gckKERNEL_Recovery(Hardware->kernel)); + break; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_BroadcastHurry +** +** The GPU is running too slow. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctUINT Urgency +** The higher the number, the higher the urgency to speed up the GPU. +** The maximum value is defined by the gcdDYNAMIC_EVENT_THRESHOLD. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_BroadcastHurry( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT Urgency + ) +{ + gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Urgency=%u", Os, Hardware, Urgency); + + /* Do whatever you need to do to speed up the GPU now. */ + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_BroadcastCalibrateSpeed +** +** Calibrate the speed of the GPU. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gckHARDWARE Hardware +** Pointer to the gckHARDWARE object. +** +** gctUINT Idle, Time +** Idle/Time will give the percentage the GPU is idle, so you can use +** this to calibrate the working point of the GPU. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_BroadcastCalibrateSpeed( + IN gckOS Os, + IN gckHARDWARE Hardware, + IN gctUINT Idle, + IN gctUINT Time + ) +{ + gcmkHEADER_ARG("Os=0x%x Hardware=0x%x Idle=%u Time=%u", + Os, Hardware, Idle, Time); + + /* Do whatever you need to do to callibrate the GPU speed. */ + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +********************************** Semaphores ********************************** +*******************************************************************************/ + +/******************************************************************************* +** +** gckOS_CreateSemaphore +** +** Create a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** OUTPUT: +** +** gctPOINTER * Semaphore +** Pointer to the variable that will receive the created semaphore. +*/ +gceSTATUS +gckOS_CreateSemaphore( + IN gckOS Os, + OUT gctPOINTER * Semaphore + ) +{ + gceSTATUS status; + struct semaphore *sem = gcvNULL; + + gcmkHEADER_ARG("Os=0x%X", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Allocate the semaphore structure. */ + sem = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | __GFP_NOWARN); + if (sem == gcvNULL) + { + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Initialize the semaphore. */ + sema_init(sem, 1); + + /* Return to caller. */ + *Semaphore = (gctPOINTER) sem; + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_AcquireSemaphore +** +** Acquire a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_AcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%08X Semaphore=0x%08X", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Acquire the semaphore. */ + if (down_interruptible((struct semaphore *) Semaphore)) + { + gcmkONERROR(gcvSTATUS_TIMEOUT); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_TryAcquireSemaphore +** +** Try to acquire a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be acquired. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_TryAcquireSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gceSTATUS status; + + gcmkHEADER_ARG("Os=0x%x", Os); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Acquire the semaphore. */ + if (down_trylock((struct semaphore *) Semaphore)) + { + /* Timeout. */ + status = gcvSTATUS_TIMEOUT; + gcmkFOOTER(); + return status; + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_ReleaseSemaphore +** +** Release a previously acquired semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be released. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_ReleaseSemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Release the semaphore. */ + up((struct semaphore *) Semaphore); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DestroySemaphore +** +** Destroy a semaphore. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Semaphore +** Pointer to the semaphore thet needs to be destroyed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySemaphore( + IN gckOS Os, + IN gctPOINTER Semaphore + ) +{ + gcmkHEADER_ARG("Os=0x%X Semaphore=0x%X", Os, Semaphore); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Free the sempahore structure. */ + kfree(Semaphore); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetProcessID +** +** Get current process ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ProcessID +** Pointer to the variable that receives the process ID. +*/ +gceSTATUS +gckOS_GetProcessID( + OUT gctUINT32_PTR ProcessID + ) +{ + /* Get process ID. */ + if (ProcessID != gcvNULL) + { + *ProcessID = _GetProcessID(); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_GetThreadID +** +** Get current thread ID. +** +** INPUT: +** +** Nothing. +** +** OUTPUT: +** +** gctUINT32_PTR ThreadID +** Pointer to the variable that receives the thread ID. +*/ +gceSTATUS +gckOS_GetThreadID( + OUT gctUINT32_PTR ThreadID + ) +{ + /* Get thread ID. */ + if (ThreadID != gcvNULL) + { + *ThreadID = _GetThreadID(); + } + + /* Success. */ + return gcvSTATUS_OK; +} + +static void galdevice_clk_enable(gckGALDEVICE device) +{ + struct clk *clk = device->clk; + + if (!clk) + return; + + if (device->clk_enabled) + return; + + clk_enable(clk); + device->clk_enabled = 1; +} + +static void galdevice_clk_disable(gckGALDEVICE device) +{ + struct clk *clk = device->clk; + + if (!clk) + return; + + if (!device->clk_enabled) + return; + + clk_disable(clk); + device->clk_enabled = 0; +} + +/******************************************************************************* +** +** gckOS_SetGPUPower +** +** Set the power of the GPU on or off. +** +** INPUT: +** +** gckOS Os +** Pointer to a gckOS object. +** +** gctBOOL Clock +** gcvTRUE to turn on the clock, or gcvFALSE to turn off the clock. +** +** gctBOOL Power +** gcvTRUE to turn on the power, or gcvFALSE to turn off the power. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetGPUPower( + IN gckOS Os, + IN gctBOOL Clock, + IN gctBOOL Power + ) +{ + gckGALDEVICE device = (gckGALDEVICE) Os->device; + + gcmkHEADER_ARG("Os=0x%X Clock=%d Power=%d", Os, Clock, Power); + + /* TODO: Put your code here. */ + if (Clock == gcvFALSE) + galdevice_clk_disable(device); + else + galdevice_clk_enable(device); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/*----------------------------------------------------------------------------*/ +/*----- Profile --------------------------------------------------------------*/ + +gceSTATUS +gckOS_GetProfileTick( + OUT gctUINT64_PTR Tick + ) +{ + struct timespec time; + + ktime_get_ts(&time); + + *Tick = time.tv_nsec + time.tv_sec * 1000000000ULL; + + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_QueryProfileTickRate( + OUT gctUINT64_PTR TickRate + ) +{ + struct timespec res; + + hrtimer_get_res(CLOCK_MONOTONIC, &res); + + *TickRate = res.tv_nsec + res.tv_sec * 1000000000ULL; + + return gcvSTATUS_OK; +} + +gctUINT32 +gckOS_ProfileToMS( + IN gctUINT64 Ticks + ) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23) + return div_u64(Ticks, 1000000); +#else + gctUINT64 rem = Ticks; + gctUINT64 b = 1000000; + gctUINT64 res, d = 1; + gctUINT32 high = rem >> 32; + + /* Reduce the thing a bit first */ + res = 0; + if (high >= 1000000) + { + high /= 1000000; + res = (gctUINT64) high << 32; + rem -= (gctUINT64) (high * 1000000) << 32; + } + + while (((gctINT64) b > 0) && (b < rem)) + { + b <<= 1; + d <<= 1; + } + + do + { + if (rem >= b) + { + rem -= b; + res += d; + } + + b >>= 1; + d >>= 1; + } + while (d); + + return (gctUINT32) res; +#endif +} + +/******************************************************************************\ +******************************* Signal Management ****************************** +\******************************************************************************/ + +#undef _GC_OBJ_ZONE +#define _GC_OBJ_ZONE gcvZONE_SIGNAL + +/******************************************************************************* +** +** gckOS_CreateSignal +** +** Create a new signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctSIGNAL * Signal +** Pointer to a variable receiving the created gctSIGNAL. +*/ +gceSTATUS +gckOS_CreateSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctSIGNAL * Signal + ) +{ + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%X ManualReset=%d", Os, ManualReset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + /* Create an event structure. */ + signal = (gcsSIGNAL_PTR) kmalloc(sizeof(gcsSIGNAL), GFP_KERNEL | __GFP_NOWARN); + + if (signal == gcvNULL) + { + gcmkFOOTER_ARG("status=%d", gcvSTATUS_OUT_OF_MEMORY); + return gcvSTATUS_OUT_OF_MEMORY; + } + + signal->manualReset = ManualReset; + init_completion(&signal->obj); + atomic_set(&signal->ref, 1); + + *Signal = (gctSIGNAL) signal; + + gcmkFOOTER_ARG("*Signal=0x%X", *Signal); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_DestroySignal +** +** Destroy a signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroySignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X", Os, Signal); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + if (atomic_dec_and_test(&signal->ref)) + { + /* Free the sgianl. */ + kfree(Signal); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_Signal +** +** Set a state of the specified signal. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_Signal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctBOOL State + ) +{ + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X State=%d", Os, Signal, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + if (State) + { + /* Set the event to a signaled state. */ + complete(&signal->obj); + } + else + { + /* Set the event to an unsignaled state. */ + INIT_COMPLETION(signal->obj); + } + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#if gcdENABLE_VG +gceSTATUS +gckOS_SetSignalVG( + IN gckOS Os, + IN gctHANDLE Process, + IN gctSIGNAL Signal + ) +{ + gceSTATUS status; + gctINT result; + struct task_struct * userTask; + struct siginfo info; + + userTask = FIND_TASK_BY_PID((pid_t) Process); + + if (userTask != gcvNULL) + { + info.si_signo = 48; + info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); + info.si_pid = 0; + info.si_uid = 0; + info.si_ptr = (gctPOINTER) Signal; + + /* Signals with numbers between 32 and 63 are real-time, + send a real-time signal to the user process. */ + result = send_sig_info(48, &info, userTask); + + printk("gckOS_SetSignalVG:0x%x\n", result); + /* Error? */ + if (result < 0) + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): an error has occurred.\n", + __FUNCTION__, __LINE__ + ); + } + else + { + status = gcvSTATUS_OK; + } + } + else + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): an error has occurred.\n", + __FUNCTION__, __LINE__ + ); + } + + /* Return status. */ + return status; +} +#endif + +/******************************************************************************* +** +** gckOS_UserSignal +** +** Set the specified signal which is owned by a process to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_UserSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process + ) +{ + gceSTATUS status; + gctSIGNAL signal; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=%d", + Os, Signal, (gctINT32) Process); + + /* Map the signal into kernel space. */ + gcmkONERROR(gckOS_MapSignal(Os, Signal, Process, &signal)); + + /* Signal. */ + status = gckOS_Signal(Os, signal, gcvTRUE); + + /* Unmap the signal */ + gcmkVERIFY_OK(gckOS_UnmapSignal(Os, Signal)); + + gcmkFOOTER(); + return status; + +OnError: + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitSignal +** +** Wait for a signal to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctUINT32 Wait + ) +{ + gceSTATUS status = gcvSTATUS_OK; + gcsSIGNAL_PTR signal; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signal = (gcsSIGNAL_PTR) Signal; + + might_sleep(); + + spin_lock_irq(&signal->obj.wait.lock); + + if (signal->obj.done) + { + if (!signal->manualReset) + { + signal->obj.done = 0; + } + + status = gcvSTATUS_OK; + } + else if (Wait == 0) + { + status = gcvSTATUS_TIMEOUT; + } + else + { + /* Convert wait to milliseconds. */ +#if gcdDETECT_TIMEOUT + gctINT timeout = (Wait == gcvINFINITE) + ? gcdINFINITE_TIMEOUT * HZ / 1000 + : Wait * HZ / 1000; + + gctUINT complained = 0; +#else + gctINT timeout = (Wait == gcvINFINITE) + ? MAX_SCHEDULE_TIMEOUT + : Wait * HZ / 1000; +#endif + + DECLARE_WAITQUEUE(wait, current); + wait.flags |= WQ_FLAG_EXCLUSIVE; + __add_wait_queue_tail(&signal->obj.wait, &wait); + + while (gcvTRUE) + { + if (signal_pending(current)) + { + /* Interrupt received. */ + status = gcvSTATUS_INTERRUPTED; + break; + } + + __set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irq(&signal->obj.wait.lock); + timeout = schedule_timeout(timeout); + spin_lock_irq(&signal->obj.wait.lock); + + if (signal->obj.done) + { + if (!signal->manualReset) + { + signal->obj.done = 0; + } + + status = gcvSTATUS_OK; + break; + } + +#if gcdDETECT_TIMEOUT + if ((Wait == gcvINFINITE) && (timeout == 0)) + { + gctUINT32 dmaAddress1, dmaAddress2; + gctUINT32 dmaState1, dmaState2; + + dmaState1 = dmaState2 = + dmaAddress1 = dmaAddress2 = 0; + + /* Verify whether DMA is running. */ + gcmkVERIFY_OK(_VerifyDMA( + Os, &dmaAddress1, &dmaAddress2, &dmaState1, &dmaState2 + )); + +#if gcdDETECT_DMA_ADDRESS + /* Dump only if DMA appears stuck. */ + if ( + (dmaAddress1 == dmaAddress2) +#if gcdDETECT_DMA_STATE + && (dmaState1 == dmaState2) +#endif + ) +#endif + { + /* Increment complain count. */ + complained += 1; + + gcmkVERIFY_OK(_DumpGPUState(Os, gcvCORE_MAJOR)); + + gcmkPRINT( + "%s(%d): signal 0x%X; forced message flush (%d).", + __FUNCTION__, __LINE__, Signal, complained + ); + + /* Flush the debug cache. */ + gcmkDEBUGFLUSH(dmaAddress2); + } + + /* Reset timeout. */ + timeout = gcdINFINITE_TIMEOUT * HZ / 1000; + } +#endif + + if (timeout == 0) + { + + status = gcvSTATUS_TIMEOUT; + break; + } + } + + __remove_wait_queue(&signal->obj.wait, &wait); + +#if gcdDETECT_TIMEOUT + if (complained) + { + gcmkPRINT( + "%s(%d): signal=0x%X; waiting done; status=%d", + __FUNCTION__, __LINE__, Signal, status + ); + } +#endif + } + + spin_unlock_irq(&signal->obj.wait.lock); + + /* Return status. */ + gcmkFOOTER_ARG("Signal=0x%X status=%d", Signal, status); + return status; +} + +/******************************************************************************* +** +** gckOS_MapSignal +** +** Map a signal in to the current process space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to tha gctSIGNAL to map. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** OUTPUT: +** +** gctSIGNAL * MappedSignal +** Pointer to a variable receiving the mapped gctSIGNAL. +*/ +gceSTATUS +gckOS_MapSignal( + IN gckOS Os, + IN gctSIGNAL Signal, + IN gctHANDLE Process, + OUT gctSIGNAL * MappedSignal + ) +{ + gctINT signalID; + gcsSIGNAL_PTR signal; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X Process=0x%X", Os, Signal, Process); + + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL); + + signalID = (gctINT) Signal - 1; + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (signalID >= 0 && signalID < Os->signal.tableLen) + { + /* It is a user space signal. */ + signal = Os->signal.table[signalID]; + + if (signal == gcvNULL) + { + gcmkONERROR(gcvSTATUS_NOT_FOUND); + } + } + else + { + /* It is a kernel space signal structure. */ + signal = (gcsSIGNAL_PTR) Signal; + } + + if (atomic_inc_return(&signal->ref) <= 1) + { + /* The previous value is 0, it has been deleted. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + + *MappedSignal = (gctSIGNAL) signal; + + /* Success. */ + gcmkFOOTER_ARG("*MappedSignal=0x%X", *MappedSignal); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_UnmapSignal +** +** Unmap a signal . +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctSIGNAL Signal +** Pointer to that gctSIGNAL mapped. +*/ +gceSTATUS +gckOS_UnmapSignal( + IN gckOS Os, + IN gctSIGNAL Signal + ) +{ + gctINT signalID; + gcsSIGNAL_PTR signal; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%X Signal=0x%X ", Os, Signal); + + gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + + signalID = (gctINT) Signal - 1; + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (signalID >= 0 && signalID < Os->signal.tableLen) + { + /* It is a user space signal. */ + signal = Os->signal.table[signalID]; + + if (signal == gcvNULL) + { + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + if (atomic_read(&signal->ref) == 1) + { + /* Update the table. */ + Os->signal.table[signalID] = gcvNULL; + + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = signalID; + } + } + + gcmkONERROR(gckOS_DestroySignal(Os, signal)); + } + else + { + /* It is a kernel space signal structure. */ + signal = (gcsSIGNAL_PTR) Signal; + + gcmkONERROR(gckOS_DestroySignal(Os, signal)); + } + + /* Release the mutex. */ + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + + /* Success. */ + gcmkFOOTER(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_CreateUserSignal +** +** Create a new signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctBOOL ManualReset +** If set to gcvTRUE, gckOS_Signal with gcvFALSE must be called in +** order to set the signal to nonsignaled state. +** If set to gcvFALSE, the signal will automatically be set to +** nonsignaled state by gckOS_WaitSignal function. +** +** OUTPUT: +** +** gctINT * SignalID +** Pointer to a variable receiving the created signal's ID. +*/ +gceSTATUS +gckOS_CreateUserSignal( + IN gckOS Os, + IN gctBOOL ManualReset, + OUT gctINT * SignalID + ) +{ + gcsSIGNAL_PTR signal = gcvNULL; + gctINT unused, currentID, tableLen; + gctPOINTER * table; + gctINT i; + gceSTATUS status; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%0x ManualReset=%d", Os, ManualReset); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(SignalID != gcvNULL); + + /* Lock the table. */ + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (Os->signal.unused < 1) + { + /* Enlarge the table. */ + table = (gctPOINTER *) kmalloc( + sizeof(gctPOINTER) * (Os->signal.tableLen + USER_SIGNAL_TABLE_LEN_INIT), + GFP_KERNEL | __GFP_NOWARN); + + if (table == gcvNULL) + { + /* Out of memory. */ + gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); + } + + memset(table + Os->signal.tableLen, 0, sizeof(gctPOINTER) * USER_SIGNAL_TABLE_LEN_INIT); + memcpy(table, Os->signal.table, sizeof(gctPOINTER) * Os->signal.tableLen); + + /* Release the old table. */ + kfree(Os->signal.table); + + /* Update the table. */ + Os->signal.table = table; + Os->signal.currentID = Os->signal.tableLen; + Os->signal.tableLen += USER_SIGNAL_TABLE_LEN_INIT; + Os->signal.unused += USER_SIGNAL_TABLE_LEN_INIT; + } + + table = Os->signal.table; + currentID = Os->signal.currentID; + tableLen = Os->signal.tableLen; + unused = Os->signal.unused; + + /* Create a new signal. */ + gcmkONERROR( + gckOS_CreateSignal(Os, ManualReset, (gctSIGNAL *) &signal)); + + /* Save the process ID. */ + signal->process = (gctHANDLE) _GetProcessID(); + + table[currentID] = signal; + + /* Plus 1 to avoid gcvNULL claims. */ + *SignalID = currentID + 1; + + /* Update the currentID. */ + if (--unused > 0) + { + for (i = 0; i < tableLen; i++) + { + if (++currentID >= tableLen) + { + /* Wrap to the begin. */ + currentID = 0; + } + + if (table[currentID] == gcvNULL) + { + break; + } + } + } + + Os->signal.table = table; + Os->signal.currentID = currentID; + Os->signal.tableLen = tableLen; + Os->signal.unused = unused; + + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + gcmkFOOTER_ARG("*SignalID=%d", gcmOPT_VALUE(SignalID)); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkONERROR( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_DestroyUserSignal +** +** Destroy a signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** The signal's ID. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestroyUserSignal( + IN gckOS Os, + IN gctINT SignalID + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%X SignalID=%d", Os, SignalID); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR( + gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): invalid signal->%d.", + __FUNCTION__, __LINE__, + (gctINT) SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + if (signal == gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): signal is gcvNULL.", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + + if (atomic_read(&signal->ref) == 1) + { + /* Update the table. */ + Os->signal.table[SignalID] = gcvNULL; + + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = SignalID; + } + } + + gcmkONERROR( + gckOS_DestroySignal(Os, signal)); + + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + + /* Success. */ + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the status. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_WaitUserSignal +** +** Wait for a signal used in the user mode to become signaled. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** Signal ID. +** +** gctUINT32 Wait +** Number of milliseconds to wait. +** Pass the value of gcvINFINITE for an infinite wait. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_WaitUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctUINT32 Wait + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%X SignalID=%d Wait=%u", Os, SignalID, Wait); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if (SignalID < 1 || SignalID > Os->signal.tableLen) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): invalid signal %d", + __FUNCTION__, __LINE__, + SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): signal is gcvNULL.", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + + status = gckOS_WaitSignal(Os, signal, Wait); + + /* Return the status. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_SignalUserSignal +** +** Set a state of the specified signal to be used in the user space. +** +** INPUT: +** +** gckOS Os +** Pointer to an gckOS object. +** +** gctINT SignalID +** SignalID. +** +** gctBOOL State +** If gcvTRUE, the signal will be set to signaled state. +** If gcvFALSE, the signal will be set to nonsignaled state. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SignalUserSignal( + IN gckOS Os, + IN gctINT SignalID, + IN gctBOOL State + ) +{ + gceSTATUS status; + gcsSIGNAL_PTR signal; + gctBOOL acquired = gcvFALSE; + + gcmkHEADER_ARG("Os=0x%X SignalID=%d State=%d", Os, SignalID, State); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkONERROR(gckOS_AcquireMutex(Os, Os->signal.lock, gcvINFINITE)); + acquired = gcvTRUE; + + if ((SignalID < 1) + || (SignalID > Os->signal.tableLen) + ) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): invalid signal->%d.", + __FUNCTION__, __LINE__, + SignalID + ); + + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + + SignalID -= 1; + + signal = Os->signal.table[SignalID]; + + gcmkONERROR(gckOS_ReleaseMutex(Os, Os->signal.lock)); + acquired = gcvFALSE; + + if (signal == gcvNULL) + { + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): signal is gcvNULL.", + __FUNCTION__, __LINE__ + ); + + gcmkONERROR(gcvSTATUS_INVALID_REQUEST); + } + + + status = gckOS_Signal(Os, signal, State); + + /* Success. */ + gcmkFOOTER(); + return status; + +OnError: + if (acquired) + { + /* Release the mutex. */ + gcmkVERIFY_OK( + gckOS_ReleaseMutex(Os, Os->signal.lock)); + } + + /* Return the staus. */ + gcmkFOOTER(); + return status; +} + +gceSTATUS +gckOS_CleanProcessSignal( + gckOS Os, + gctHANDLE Process + ) +{ + gctINT signal; + + gcmkHEADER_ARG("Os=0x%X Process=%d", Os, Process); + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + gcmkVERIFY_OK(gckOS_AcquireMutex(Os, + Os->signal.lock, + gcvINFINITE + )); + + if (Os->signal.unused == Os->signal.tableLen) + { + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + } + + for (signal = 0; signal < Os->signal.tableLen; signal++) + { + if (Os->signal.table[signal] != gcvNULL && + ((gcsSIGNAL_PTR)Os->signal.table[signal])->process == Process) + { + gckOS_DestroySignal(Os, Os->signal.table[signal]); + + /* Update the signal table. */ + Os->signal.table[signal] = gcvNULL; + if (Os->signal.unused++ == 0) + { + Os->signal.currentID = signal; + } + } + } + + gcmkVERIFY_OK(gckOS_ReleaseMutex(Os, + Os->signal.lock + )); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +#if gcdENABLE_VG +gceSTATUS +gckOS_CreateSemaphoreVG( + IN gckOS Os, + OUT gctSEMAPHORE * Semaphore + ) +{ + gceSTATUS status; + struct semaphore * newSemaphore; + + gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + do + { + /* Allocate the semaphore structure. */ + newSemaphore = (struct semaphore *)kmalloc(gcmSIZEOF(struct semaphore), GFP_KERNEL | __GFP_NOWARN); + if (newSemaphore == gcvNULL) + { + gcmkERR_BREAK(gcvSTATUS_OUT_OF_MEMORY); + } + + /* Initialize the semaphore. */ + sema_init(newSemaphore, 0); + + /* Set the handle. */ + * Semaphore = (gctSEMAPHORE) newSemaphore; + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return the status. */ + return status; +} + + +gceSTATUS +gckOS_IncrementSemaphore( + IN gckOS Os, + IN gctSEMAPHORE Semaphore + ) +{ + gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + /* Increment the semaphore's count. */ + up((struct semaphore *) Semaphore); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_DecrementSemaphore( + IN gckOS Os, + IN gctSEMAPHORE Semaphore + ) +{ + gceSTATUS status; + gctINT result; + + gcmkHEADER_ARG("Os=0x%X Semaphore=0x%x", Os, Semaphore); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Semaphore != gcvNULL); + + do + { + /* Decrement the semaphore's count. If the count is zero, wait + until it gets incremented. */ + result = down_interruptible((struct semaphore *) Semaphore); + + /* Signal received? */ + if (result != 0) + { + status = gcvSTATUS_TERMINATE; + break; + } + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return the status. */ + return status; +} + +/******************************************************************************* +** +** gckOS_SetSignal +** +** Set the specified signal to signaled state. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctHANDLE Process +** Handle of process owning the signal. +** +** gctSIGNAL Signal +** Pointer to the gctSIGNAL. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_SetSignal( + IN gckOS Os, + IN gctHANDLE Process, + IN gctSIGNAL Signal + ) +{ + gceSTATUS status; + gctINT result; + struct task_struct * userTask; + struct siginfo info; + + userTask = FIND_TASK_BY_PID((pid_t) Process); + + if (userTask != gcvNULL) + { + info.si_signo = 48; + info.si_code = __SI_CODE(__SI_RT, SI_KERNEL); + info.si_pid = 0; + info.si_uid = 0; + info.si_ptr = (gctPOINTER) Signal; + + /* Signals with numbers between 32 and 63 are real-time, + send a real-time signal to the user process. */ + result = send_sig_info(48, &info, userTask); + + /* Error? */ + if (result < 0) + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): an error has occurred.\n", + __FUNCTION__, __LINE__ + ); + } + else + { + status = gcvSTATUS_OK; + } + } + else + { + status = gcvSTATUS_GENERIC_IO; + + gcmkTRACE( + gcvLEVEL_ERROR, + "%s(%d): an error has occurred.\n", + __FUNCTION__, __LINE__ + ); + } + + /* Return status. */ + return status; +} + +/******************************************************************************\ +******************************** Thread Object ********************************* +\******************************************************************************/ + +gceSTATUS +gckOS_StartThread( + IN gckOS Os, + IN gctTHREADFUNC ThreadFunction, + IN gctPOINTER ThreadParameter, + OUT gctTHREAD * Thread + ) +{ + gceSTATUS status; + struct task_struct * thread; + + gcmkHEADER_ARG("Os=0x%X ", Os); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(ThreadFunction != gcvNULL); + gcmkVERIFY_ARGUMENT(Thread != gcvNULL); + + do + { + /* Create the thread. */ + thread = kthread_create( + ThreadFunction, + ThreadParameter, + "Vivante Kernel Thread" + ); + + /* Failed? */ + if (IS_ERR(thread)) + { + status = gcvSTATUS_GENERIC_IO; + break; + } + + /* Start the thread. */ + wake_up_process(thread); + + /* Set the thread handle. */ + * Thread = (gctTHREAD) thread; + + /* Success. */ + status = gcvSTATUS_OK; + } + while (gcvFALSE); + + gcmkFOOTER(); + /* Return the status. */ + return status; +} + +gceSTATUS +gckOS_StopThread( + IN gckOS Os, + IN gctTHREAD Thread + ) +{ + gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Thread != gcvNULL); + + /* Thread should have already been enabled to terminate. */ + kthread_stop((struct task_struct *) Thread); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +gceSTATUS +gckOS_VerifyThread( + IN gckOS Os, + IN gctTHREAD Thread + ) +{ + gcmkHEADER_ARG("Os=0x%X Thread=0x%x", Os, Thread); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Thread != gcvNULL); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} +#endif + +/******************************************************************************* +** +** gckOS_DumpGPUState +** +** Dump GPU state. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gceCORE Core +** The core type of kernel. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DumpGPUState( + IN gckOS Os, + IN gceCORE Core + ) +{ + gcmkHEADER_ARG("Os=0x%X Core=%d", Os, Core); + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + + _DumpGPUState(Os, Core); + + gcmkFOOTER_NO(); + /* Success. */ + return gcvSTATUS_OK; +} + +/******************************************************************************\ +******************************** Software Timer ******************************** +\******************************************************************************/ + +void +_TimerFunction( + struct work_struct * work + ) +{ + gcsOSTIMER_PTR timer = (gcsOSTIMER_PTR)work; + + gctTIMERFUNCTION function = timer->function; + + function(timer->data); +} + +/******************************************************************************* +** +** gckOS_CreateTimer +** +** Create a software timer. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctTIMERFUNCTION Function. +** Pointer to a call back function which will be called when timer is +** expired. +** +** gctPOINTER Data. +** Private data which will be passed to call back function. +** +** OUTPUT: +** +** gctPOINTER * Timer +** Pointer to a variable receiving the created timer. +*/ +gceSTATUS +gckOS_CreateTimer( + IN gckOS Os, + IN gctTIMERFUNCTION Function, + IN gctPOINTER Data, + OUT gctPOINTER * Timer + ) +{ + gceSTATUS status; + gcsOSTIMER_PTR pointer; + gcmkHEADER_ARG("Os=0x%X Function=0x%X Data=0x%X", Os, Function, Data); + + /* Verify the arguments. */ + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Timer != gcvNULL); + + gcmkONERROR(gckOS_Allocate(Os, sizeof(gcsOSTIMER), (gctPOINTER)&pointer)); + + pointer->function = Function; + pointer->data = Data; + + INIT_DELAYED_WORK(&pointer->work, _TimerFunction); + + *Timer = pointer; + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; + +OnError: + gcmkFOOTER(); + return status; +} + +/******************************************************************************* +** +** gckOS_DestoryTimer +** +** Destory a software timer. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Timer +** Pointer to the timer to be destoryed. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_DestoryTimer( + IN gckOS Os, + IN gctPOINTER Timer + ) +{ + gcsOSTIMER_PTR timer; + gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer); + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Timer != gcvNULL); + + timer = (gcsOSTIMER_PTR)Timer; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) + cancel_delayed_work_sync(&timer->work); +#else + cancel_delayed_work(&timer->work); + flush_workqueue(Os->workqueue); +#endif + + gcmkVERIFY_OK(gcmkOS_SAFE_FREE(Os, Timer)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_StartTimer +** +** Schedule a software timer. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Timer +** Pointer to the timer to be scheduled. +** +** gctUINT32 Delay +** Delay in milliseconds. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_StartTimer( + IN gckOS Os, + IN gctPOINTER Timer, + IN gctUINT32 Delay + ) +{ + gcsOSTIMER_PTR timer; + + gcmkHEADER_ARG("Os=0x%X Timer=0x%X Delay=%u", Os, Timer, Delay); + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Timer != gcvNULL); + gcmkVERIFY_ARGUMENT(Delay != 0); + + timer = (gcsOSTIMER_PTR)Timer; + + if (unlikely(delayed_work_pending(&timer->work))) + { + cancel_delayed_work(&timer->work); + } + + queue_delayed_work(Os->workqueue, &timer->work, msecs_to_jiffies(Delay)); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} + +/******************************************************************************* +** +** gckOS_StopTimer +** +** Cancel a unscheduled timer. +** +** INPUT: +** +** gckOS Os +** Pointer to the gckOS object. +** +** gctPOINTER Timer +** Pointer to the timer to be cancel. +** +** OUTPUT: +** +** Nothing. +*/ +gceSTATUS +gckOS_StopTimer( + IN gckOS Os, + IN gctPOINTER Timer + ) +{ + gcsOSTIMER_PTR timer; + gcmkHEADER_ARG("Os=0x%X Timer=0x%X", Os, Timer); + + gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); + gcmkVERIFY_ARGUMENT(Timer != gcvNULL); + + timer = (gcsOSTIMER_PTR)Timer; + + cancel_delayed_work(&timer->work); + + gcmkFOOTER_NO(); + return gcvSTATUS_OK; +} diff --git a/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.h b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.h new file mode 100644 index 0000000..021e77f --- /dev/null +++ b/kernel_drivers/v4/hal/os/linux/kernel/gc_hal_kernel_os.h @@ -0,0 +1,88 @@ +/**************************************************************************** +* +* Copyright (C) 2005 - 2012 by Vivante Corp. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the license, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +* +*****************************************************************************/ + + + + +#ifndef __gc_hal_kernel_os_h_ +#define __gc_hal_kernel_os_h_ + +typedef struct _LINUX_MDL_MAP +{ + gctINT pid; + gctPOINTER vmaAddr; + struct vm_area_struct * vma; + struct _LINUX_MDL_MAP * next; +} +LINUX_MDL_MAP; + +typedef struct _LINUX_MDL_MAP * PLINUX_MDL_MAP; + +typedef struct _LINUX_MDL +{ + gctINT pid; + char * addr; + + union _pages + { + /* Pointer to a array of pages. */ + struct page * contiguousPages; + /* Pointer to a array of pointers to page. */ + struct page ** nonContiguousPages; + } + u; + +#ifdef NO_DMA_COHERENT + gctPOINTER kaddr; +#endif /* NO_DMA_COHERENT */ + + gctINT numPages; + gctINT pagedMem; + gctBOOL contiguous; + dma_addr_t dmaHandle; + PLINUX_MDL_MAP maps; + struct _LINUX_MDL * prev; + struct _LINUX_MDL * next; +} +LINUX_MDL, *PLINUX_MDL; + +extern PLINUX_MDL_MAP +FindMdlMap( + IN PLINUX_MDL Mdl, + IN gctINT PID + ); + +typedef struct _DRIVER_ARGS +{ + gctPOINTER InputBuffer; + gctUINT32 InputBufferSize; + gctPOINTER OutputBuffer; + gctUINT32 OutputBufferSize; +} +DRIVER_ARGS; + +/* Cleanup the signal table. */ +gceSTATUS +gckOS_CleanProcessSignal( + gckOS Os, + gctHANDLE Process + ); + +#endif /* __gc_hal_kernel_os_h_ */ |