diff --git a/patch/kernel/sun8i-default/0016-r4p0-00rel0.patch.disabled b/patch/kernel/sun8i-default/0016-r4p0-00rel0.patch.disabled new file mode 100644 index 0000000000..66da2049ee --- /dev/null +++ b/patch/kernel/sun8i-default/0016-r4p0-00rel0.patch.disabled @@ -0,0 +1,47787 @@ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kbuild b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kbuild +new file mode 100644 +index 0000000..22b136c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kbuild +@@ -0,0 +1,213 @@ ++# ++# Copyright (C) 2010-2011 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++# This file is called by the Linux build system. ++ ++# set up defaults if not defined by the user ++TIMESTAMP ?= default ++OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 16 ++USING_GPU_UTILIZATION ?= 1 ++PROFILING_SKIP_PP_JOBS ?= 0 ++PROFILING_SKIP_PP_AND_GP_JOBS ?= 0 ++MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP ?= 0 ++MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED ?= 0 ++MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS ?= 0 ++MALI_UPPER_HALF_SCHEDULING ?= 1 ++MALI_ENABLE_CPU_CYCLES ?= 0 ++ ++# For customer releases the Linux Device Drivers will be provided as ARM proprietary and GPL releases: ++# The ARM proprietary product will only include the license/proprietary directory ++# The GPL product will only include the license/gpl directory ++ifeq ($(wildcard $(src)/linux/license/gpl/*),) ++ ccflags-y += -I$(src)/linux/license/proprietary ++ ifeq ($(CONFIG_MALI400_PROFILING),y) ++ $(error Profiling is incompatible with non-GPL license) ++ endif ++ ifeq ($(CONFIG_PM_RUNTIME),y) ++ $(error Runtime PM is incompatible with non-GPL license) ++ endif ++ ifeq ($(CONFIG_DMA_SHARED_BUFFER),y) ++ $(error DMA-BUF is incompatible with non-GPL license) ++ endif ++ $(error Linux Device integration is incompatible with non-GPL license) ++else ++ ccflags-y += -I$(src)/linux/license/gpl ++endif ++ ++mali-y += \ ++ linux/mali_osk_atomics.o \ ++ linux/mali_osk_irq.o \ ++ linux/mali_osk_wq.o \ ++ linux/mali_osk_locks.o \ ++ linux/mali_osk_wait_queue.o \ ++ linux/mali_osk_low_level_mem.o \ ++ linux/mali_osk_math.o \ ++ linux/mali_osk_memory.o \ ++ linux/mali_osk_misc.o \ ++ linux/mali_osk_mali.o \ ++ linux/mali_osk_notification.o \ ++ linux/mali_osk_time.o \ ++ linux/mali_osk_timers.o ++ ++mali-y += linux/mali_memory.o linux/mali_memory_os_alloc.o ++mali-y += linux/mali_memory_external.o ++mali-y += linux/mali_memory_block_alloc.o ++ ++mali-y += \ ++ linux/mali_ukk_mem.o \ ++ linux/mali_ukk_gp.o \ ++ linux/mali_ukk_pp.o \ ++ linux/mali_ukk_core.o \ ++ linux/mali_ukk_soft_job.o \ ++ linux/mali_ukk_timeline.o ++ ++# Source files which always are included in a build ++mali-y += \ ++ linux/mali_platform.o\ ++ common/mali_kernel_core.o \ ++ linux/mali_kernel_linux.o \ ++ common/mali_kernel_descriptor_mapping.o \ ++ common/mali_session.o \ ++ linux/mali_device_pause_resume.o \ ++ common/mali_kernel_vsync.o \ ++ linux/mali_ukk_vsync.o \ ++ linux/mali_kernel_sysfs.o \ ++ common/mali_mmu.o \ ++ common/mali_mmu_page_directory.o \ ++ common/mali_mem_validation.o \ ++ common/mali_hw_core.o \ ++ common/mali_gp.o \ ++ common/mali_pp.o \ ++ common/mali_pp_job.o \ ++ common/mali_gp_job.o \ ++ common/mali_soft_job.o \ ++ common/mali_scheduler.o \ ++ common/mali_gp_scheduler.o \ ++ common/mali_pp_scheduler.o \ ++ common/mali_group.o \ ++ common/mali_dlbu.o \ ++ common/mali_broadcast.o \ ++ common/mali_pm.o \ ++ common/mali_pmu.o \ ++ common/mali_user_settings_db.o \ ++ common/mali_kernel_utilization.o \ ++ common/mali_l2_cache.o \ ++ common/mali_dma.o \ ++ common/mali_timeline.o \ ++ common/mali_timeline_fence_wait.o \ ++ common/mali_timeline_sync_fence.o \ ++ common/mali_spinlock_reentrant.o \ ++ common/mali_pm_domain.o \ ++ linux/mali_osk_pm.o \ ++ linux/mali_pmu_power_up_down.o \ ++ __malidrv_build_info.o ++ ++ifneq ($(MALI_PLATFORM_FILES),) ++ mali-y += $(MALI_PLATFORM_FILES:.c=.o) ++endif ++ ++mali-$(CONFIG_MALI400_PROFILING) += linux/mali_ukk_profiling.o ++mali-$(CONFIG_MALI400_PROFILING) += linux/mali_osk_profiling.o ++ ++mali-$(CONFIG_MALI400_INTERNAL_PROFILING) += linux/mali_profiling_internal.o timestamp-$(TIMESTAMP)/mali_timestamp.o ++ccflags-$(CONFIG_MALI400_INTERNAL_PROFILING) += -I$(src)/timestamp-$(TIMESTAMP) ++ ++mali-$(CONFIG_DMA_SHARED_BUFFER) += linux/mali_memory_dma_buf.o ++mali-$(CONFIG_SYNC) += linux/mali_sync.o ++ ++mali-$(CONFIG_MALI400_UMP) += linux/mali_memory_ump.o ++ ++mali-$(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) += common/mali_power_performance_policy.o ++ ++# Tell the Linux build system from which .o file to create the kernel module ++obj-$(CONFIG_MALI400) := mali.o ++ ++ccflags-y += $(EXTRA_DEFINES) ++ ++# Set up our defines, which will be passed to gcc ++ccflags-y += -DPROFILING_SKIP_PP_JOBS=$(PROFILING_SKIP_PP_JOBS) ++ccflags-y += -DPROFILING_SKIP_PP_AND_GP_JOBS=$(PROFILING_SKIP_PP_AND_GP_JOBS) ++ ++ccflags-y += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP) ++ccflags-y += -DMALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED=$(MALI_PP_SCHEDULER_KEEP_SUB_JOB_STARTS_ALIGNED) ++ccflags-y += -DMALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS=$(MALI_PP_SCHEDULER_FORCE_NO_JOB_OVERLAP_BETWEEN_APPS) ++ccflags-y += -DMALI_STATE_TRACKING=1 ++ccflags-y += -DMALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB) ++ccflags-y += -DUSING_GPU_UTILIZATION=$(USING_GPU_UTILIZATION) ++ccflags-y += -DMALI_ENABLE_CPU_CYCLES=$(MALI_ENABLE_CPU_CYCLES) ++ ++ifeq ($(MALI_UPPER_HALF_SCHEDULING),1) ++ ccflags-y += -DMALI_UPPER_HALF_SCHEDULING ++endif ++ ++ccflags-$(CONFIG_MALI400_UMP) += -I$(src)/../../ump/include/ump ++ccflags-$(CONFIG_MALI400_DEBUG) += -DDEBUG ++ ++# Use our defines when compiling ++ccflags-y += -I$(src) -I$(src)/include -I$(src)/common -I$(src)/linux -I$(src)/platform ++ ++# Get subversion revision number, fall back to only ${MALI_RELEASE_NAME} if no svn info is available ++MALI_RELEASE_NAME=$(shell cat $(src)/.version 2> /dev/null) ++ ++SVN_INFO = (cd $(src); svn info 2>/dev/null) ++ ++ifneq ($(shell $(SVN_INFO) 2>/dev/null),) ++# SVN detected ++SVN_REV := $(shell $(SVN_INFO) | grep '^Revision: '| sed -e 's/^Revision: //' 2>/dev/null) ++DRIVER_REV := $(MALI_RELEASE_NAME)-r$(SVN_REV) ++CHANGE_DATE := $(shell $(SVN_INFO) | grep '^Last Changed Date: ' | cut -d: -f2- | cut -b2-) ++CHANGED_REVISION := $(shell $(SVN_INFO) | grep '^Last Changed Rev: ' | cut -d: -f2- | cut -b2-) ++REPO_URL := $(shell $(SVN_INFO) | grep '^URL: ' | cut -d: -f2- | cut -b2-) ++ ++else # SVN ++GIT_REV := $(shell cd $(src); git describe --always 2>/dev/null) ++ifneq ($(GIT_REV),) ++# Git detected ++DRIVER_REV := $(MALI_RELEASE_NAME)-$(GIT_REV) ++CHANGE_DATE := $(shell cd $(src); git log -1 --format="%ci") ++CHANGED_REVISION := $(GIT_REV) ++REPO_URL := $(shell cd $(src); git describe --all --always 2>/dev/null) ++ ++else # Git ++# No Git or SVN detected ++DRIVER_REV := $(MALI_RELEASE_NAME) ++CHANGE_DATE := $(MALI_RELEASE_NAME) ++CHANGED_REVISION := $(MALI_RELEASE_NAME) ++endif ++endif ++ ++ccflags-y += -DSVN_REV_STRING=\"$(DRIVER_REV)\" ++ ++VERSION_STRINGS := ++VERSION_STRINGS += API_VERSION=$(shell cd $(src); grep "\#define _MALI_API_VERSION" $(FILES_PREFIX)include/linux/mali/mali_utgard_uk_types.h | cut -d' ' -f 3 ) ++VERSION_STRINGS += REPO_URL=$(REPO_URL) ++VERSION_STRINGS += REVISION=$(DRIVER_REV) ++VERSION_STRINGS += CHANGED_REVISION=$(CHANGED_REVISION) ++VERSION_STRINGS += CHANGE_DATE=$(CHANGE_DATE) ++VERSION_STRINGS += BUILD_DATE=$(shell date) ++ifdef CONFIG_MALI400_DEBUG ++VERSION_STRINGS += BUILD=debug ++else ++VERSION_STRINGS += BUILD=release ++endif ++VERSION_STRINGS += TARGET_PLATFORM=$(TARGET_PLATFORM) ++VERSION_STRINGS += MALI_PLATFORM=$(MALI_PLATFORM) ++VERSION_STRINGS += KDIR=$(KDIR) ++VERSION_STRINGS += OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=$(OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB) ++VERSION_STRINGS += USING_UMP=$(CONFIG_MALI400_UMP) ++VERSION_STRINGS += USING_PROFILING=$(CONFIG_MALI400_PROFILING) ++VERSION_STRINGS += USING_INTERNAL_PROFILING=$(CONFIG_MALI400_INTERNAL_PROFILING) ++VERSION_STRINGS += USING_GPU_UTILIZATION=$(USING_GPU_UTILIZATION) ++VERSION_STRINGS += USING_POWER_PERFORMANCE_POLICY=$(CONFIG_POWER_PERFORMANCE_POLICY) ++VERSION_STRINGS += MALI_UPPER_HALF_SCHEDULING=$(MALI_UPPER_HALF_SCHEDULING) ++ ++# Create file with Mali driver configuration ++$(src)/__malidrv_build_info.c: ++ @echo 'const char *__malidrv_build_info(void) { return "malidrv: $(VERSION_STRINGS)";}' > $(src)/__malidrv_build_info.c +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kconfig b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kconfig +new file mode 100644 +index 0000000..477e6b6 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Kconfig +@@ -0,0 +1,81 @@ ++config MALI400 ++ tristate "Mali-300/400/450 support" ++ depends on ARM ++ select DMA_SHARED_BUFFER ++ ---help--- ++ This enables support for the ARM Mali-300, Mali-400, and Mali-450 ++ GPUs. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called mali. ++ ++config MALI450 ++ bool "Enable Mali-450 support" ++ depends on MALI400 ++ ---help--- ++ This enables support for Mali-450 specific features. ++ ++config MALI400_DEBUG ++ bool "Enable debug in Mali driver" ++ depends on MALI400 ++ ---help--- ++ This enabled extra debug checks and messages in the Mali driver. ++ ++config MALI400_PROFILING ++ bool "Enable Mali profiling" ++ depends on MALI400 ++ select TRACEPOINTS ++ default y ++ ---help--- ++ This enables gator profiling of Mali GPU events. ++ ++config MALI400_INTERNAL_PROFILING ++ bool "Enable internal Mali profiling API" ++ depends on MALI400_PROFILING ++ default n ++ ---help--- ++ This enables the internal legacy Mali profiling API. ++ ++config MALI400_UMP ++ bool "Enable UMP support" ++ depends on MALI400 ++ ---help--- ++ This enables support for the UMP memory sharing API in the Mali driver. ++ ++config MALI400_POWER_PERFORMANCE_POLICY ++ bool "Enable Mali power performance policy" ++ depends on ARM ++ default n ++ ---help--- ++ This enables support for dynamic performance scaling of Mali with the goal of lowering power consumption. ++ ++config MALI_DMA_BUF_MAP_ON_ATTACH ++ bool "Map dma-buf attachments on attach" ++ depends on MALI400 && DMA_SHARED_BUFFER ++ default y ++ ---help--- ++ This makes the Mali driver map dma-buf attachments after doing ++ attach. If this is not set the dma-buf attachments will be mapped for ++ every time the GPU need to access the buffer. ++ ++ Mapping for each access can cause lower performance. ++ ++config MALI_SHARED_INTERRUPTS ++ bool "Support for shared interrupts" ++ depends on MALI400 ++ default n ++ ---help--- ++ Adds functionality required to properly support shared interrupts. Without this support, ++ the device driver will fail during insmod if it detects shared interrupts. This also ++ works when the GPU is not using shared interrupts, but might have a slight performance ++ impact. ++ ++config MALI_PMU_PARALLEL_POWER_UP ++ bool "Power up Mali PMU domains in parallel" ++ depends on MALI400 ++ default n ++ ---help--- ++ This makes the Mali driver power up all PMU power domains in parallel, instead of ++ powering up domains one by one, with a slight delay in between. Powering on all power ++ domains at the same time may cause peak currents higher than what some systems can handle. ++ These systems must not enable this option. +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Makefile b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Makefile +new file mode 100644 +index 0000000..c1b0091 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/Makefile +@@ -0,0 +1,159 @@ ++# ++# Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++USE_UMPV2=0 ++USING_PROFILING ?= 1 ++USING_INTERNAL_PROFILING ?= 0 ++USING_POWER_PERFORMANCE_POLICY ?= 0 ++MALI_HEATMAPS_ENABLED ?= 0 ++MALI_DMA_BUF_MAP_ON_ATTACH ?= 1 ++MALI_PMU_PARALLEL_POWER_UP ?= 0 ++ ++# The Makefile sets up "arch" based on the CONFIG, creates the version info ++# string and the __malidrv_build_info.c file, and then call the Linux build ++# system to actually build the driver. After that point the Kbuild file takes ++# over. ++ ++# set up defaults if not defined by the user ++ARCH ?= arm ++ ++OSKOS=linux ++FILES_PREFIX= ++ ++check_cc2 = \ ++ $(shell if $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; \ ++ then \ ++ echo "$(2)"; \ ++ else \ ++ echo "$(3)"; \ ++ fi ;) ++ ++# This conditional makefile exports the global definition ARM_INTERNAL_BUILD. Customer releases will not include arm_internal.mak ++-include ../../../arm_internal.mak ++ ++# Give warning of old config parameters are used ++ifneq ($(CONFIG),) ++$(warning "You have specified the CONFIG variable which is no longer in used. Use TARGET_PLATFORM instead.") ++endif ++ ++ifneq ($(CPU),) ++$(warning "You have specified the CPU variable which is no longer in used. Use TARGET_PLATFORM instead.") ++endif ++ ++# Include the mapping between TARGET_PLATFORM and KDIR + MALI_PLATFORM ++-include MALI_CONFIGURATION ++export KDIR ?= $(KDIR-$(TARGET_PLATFORM)) ++export MALI_PLATFORM ?= $(MALI_PLATFORM-$(TARGET_PLATFORM)) ++ ++ifneq ($(TARGET_PLATFORM),) ++ifeq ($(MALI_PLATFORM),) ++$(error "Invalid TARGET_PLATFORM: $(TARGET_PLATFORM)") ++endif ++endif ++ ++# validate lookup result ++ifeq ($(KDIR),) ++$(error No KDIR found for platform $(TARGET_PLATFORM)) ++endif ++ ++ ++ifeq ($(USING_UMP),1) ++export CONFIG_MALI400_UMP=y ++export EXTRA_DEFINES += -DCONFIG_MALI400_UMP=1 ++ifeq ($(USE_UMPV2),1) ++UMP_SYMVERS_FILE ?= ../umpv2/Module.symvers ++else ++UMP_SYMVERS_FILE ?= ../ump/Module.symvers ++endif ++KBUILD_EXTRA_SYMBOLS = $(realpath $(UMP_SYMVERS_FILE)) ++$(warning $(KBUILD_EXTRA_SYMBOLS)) ++endif ++ ++# Define host system directory ++KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build ++ ++include $(KDIR)/.config ++ ++ifeq ($(ARCH), arm) ++# when compiling for ARM we're cross compiling ++export CROSS_COMPILE ?= $(call check_cc2, arm-linux-gnueabi-gcc, arm-linux-gnueabi-, arm-none-linux-gnueabi-) ++endif ++ ++# report detected/selected settings ++ifdef ARM_INTERNAL_BUILD ++$(warning TARGET_PLATFORM $(TARGET_PLATFORM)) ++$(warning KDIR $(KDIR)) ++$(warning MALI_PLATFORM $(MALI_PLATFORM)) ++endif ++ ++# Set up build config ++export CONFIG_MALI400=m ++export CONFIG_MALI450=y ++ ++export EXTRA_DEFINES += -DCONFIG_MALI400=1 ++export EXTRA_DEFINES += -DCONFIG_MALI450=1 ++ ++ifneq ($(MALI_PLATFORM),) ++export EXTRA_DEFINES += -DMALI_FAKE_PLATFORM_DEVICE=1 ++export MALI_PLATFORM_FILES = $(wildcard platform/$(MALI_PLATFORM)/*.c) ++endif ++ ++ifeq ($(USING_PROFILING),1) ++ifeq ($(CONFIG_TRACEPOINTS),) ++$(warning CONFIG_TRACEPOINTS required for profiling) ++else ++export CONFIG_MALI400_PROFILING=y ++export EXTRA_DEFINES += -DCONFIG_MALI400_PROFILING=1 ++ifeq ($(USING_INTERNAL_PROFILING),1) ++export CONFIG_MALI400_INTERNAL_PROFILING=y ++export EXTRA_DEFINES += -DCONFIG_MALI400_INTERNAL_PROFILING=1 ++endif ++ifeq ($(MALI_HEATMAPS_ENABLED),1) ++export MALI_HEATMAPS_ENABLED=y ++export EXTRA_DEFINES += -DCONFIG_MALI400_HEATMAPS_ENABLED ++endif ++endif ++endif ++ ++ifeq ($(MALI_DMA_BUF_MAP_ON_ATTACH),1) ++export CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH=y ++export EXTRA_DEFINES += -DCONFIG_MALI_DMA_BUF_MAP_ON_ATTACH ++endif ++ ++ifeq ($(MALI_SHARED_INTERRUPTS),1) ++export CONFIG_MALI_SHARED_INTERRUPTS=y ++export EXTRA_DEFINES += -DCONFIG_MALI_SHARED_INTERRUPTS ++endif ++ ++ifeq ($(USING_POWER_PERFORMANCE_POLICY),1) ++export CONFIG_MALI400_POWER_PERFORMANCE_POLICY=y ++export EXTRA_DEFINES += -DCONFIG_MALI400_POWER_PERFORMANCE_POLICY ++endif ++ ++ifeq ($(MALI_PMU_PARALLEL_POWER_UP),1) ++export CONFIG_MALI_PMU_PARALLEL_POWER_UP=y ++export EXTRA_DEFINES += -DCONFIG_MALI_PMU_PARALLEL_POWER_UP ++endif ++ ++ifneq ($(BUILD),release) ++export CONFIG_MALI400_DEBUG=y ++endif ++ ++all: $(UMP_SYMVERS_FILE) ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) modules ++ @rm $(FILES_PREFIX)__malidrv_build_info.c $(FILES_PREFIX)__malidrv_build_info.o ++ ++clean: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean ++ ++kernelrelease: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) kernelrelease ++ ++export CONFIG KBUILD_EXTRA_SYMBOLS +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.c +new file mode 100644 +index 0000000..83cb869 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.c +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_broadcast.h" ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++ ++static const int bcast_unit_reg_size = 0x1000; ++static const int bcast_unit_addr_broadcast_mask = 0x0; ++static const int bcast_unit_addr_irq_override_mask = 0x4; ++ ++struct mali_bcast_unit { ++ struct mali_hw_core hw_core; ++ u32 current_mask; ++}; ++ ++struct mali_bcast_unit *mali_bcast_unit_create(const _mali_osk_resource_t *resource) ++{ ++ struct mali_bcast_unit *bcast_unit = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(resource); ++ MALI_DEBUG_PRINT(2, ("Mali Broadcast unit: Creating Mali Broadcast unit: %s\n", resource->description)); ++ ++ bcast_unit = _mali_osk_malloc(sizeof(struct mali_bcast_unit)); ++ if (NULL == bcast_unit) { ++ MALI_PRINT_ERROR(("Mali Broadcast unit: Failed to allocate memory for Broadcast unit\n")); ++ return NULL; ++ } ++ ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&bcast_unit->hw_core, resource, bcast_unit_reg_size)) { ++ bcast_unit->current_mask = 0; ++ mali_bcast_reset(bcast_unit); ++ ++ return bcast_unit; ++ } else { ++ MALI_PRINT_ERROR(("Mali Broadcast unit: Failed map broadcast unit\n")); ++ } ++ ++ _mali_osk_free(bcast_unit); ++ ++ return NULL; ++} ++ ++void mali_bcast_unit_delete(struct mali_bcast_unit *bcast_unit) ++{ ++ MALI_DEBUG_ASSERT_POINTER(bcast_unit); ++ ++ mali_hw_core_delete(&bcast_unit->hw_core); ++ _mali_osk_free(bcast_unit); ++} ++ ++void mali_bcast_add_group(struct mali_bcast_unit *bcast_unit, struct mali_group *group) ++{ ++ u32 bcast_id; ++ u32 broadcast_mask; ++ ++ MALI_DEBUG_ASSERT_POINTER(bcast_unit); ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ bcast_id = mali_pp_core_get_bcast_id(mali_group_get_pp_core(group)); ++ ++ broadcast_mask = bcast_unit->current_mask; ++ ++ broadcast_mask |= (bcast_id); /* add PP core to broadcast */ ++ broadcast_mask |= (bcast_id << 16); /* add MMU to broadcast */ ++ ++ /* store mask so we can restore on reset */ ++ bcast_unit->current_mask = broadcast_mask; ++} ++ ++void mali_bcast_remove_group(struct mali_bcast_unit *bcast_unit, struct mali_group *group) ++{ ++ u32 bcast_id; ++ u32 broadcast_mask; ++ ++ MALI_DEBUG_ASSERT_POINTER(bcast_unit); ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ bcast_id = mali_pp_core_get_bcast_id(mali_group_get_pp_core(group)); ++ ++ broadcast_mask = bcast_unit->current_mask; ++ ++ broadcast_mask &= ~((bcast_id << 16) | bcast_id); ++ ++ /* store mask so we can restore on reset */ ++ bcast_unit->current_mask = broadcast_mask; ++} ++ ++void mali_bcast_reset(struct mali_bcast_unit *bcast_unit) ++{ ++ MALI_DEBUG_ASSERT_POINTER(bcast_unit); ++ ++ /* set broadcast mask */ ++ mali_hw_core_register_write(&bcast_unit->hw_core, ++ bcast_unit_addr_broadcast_mask, ++ bcast_unit->current_mask); ++ ++ /* set IRQ override mask */ ++ mali_hw_core_register_write(&bcast_unit->hw_core, ++ bcast_unit_addr_irq_override_mask, ++ bcast_unit->current_mask & 0xFF); ++} ++ ++void mali_bcast_disable(struct mali_bcast_unit *bcast_unit) ++{ ++ MALI_DEBUG_ASSERT_POINTER(bcast_unit); ++ ++ /* set broadcast mask */ ++ mali_hw_core_register_write(&bcast_unit->hw_core, ++ bcast_unit_addr_broadcast_mask, ++ 0x0); ++ ++ /* set IRQ override mask */ ++ mali_hw_core_register_write(&bcast_unit->hw_core, ++ bcast_unit_addr_irq_override_mask, ++ 0x0); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.h +new file mode 100644 +index 0000000..95bc9bb +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_broadcast.h +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/* ++ * Interface for the broadcast unit on Mali-450. ++ * ++ * - Represents up to 8 × (MMU + PP) pairs. ++ * - Supports dynamically changing which (MMU + PP) pairs receive the broadcast by ++ * setting a mask. ++ */ ++ ++#include "mali_hw_core.h" ++#include "mali_group.h" ++ ++struct mali_bcast_unit; ++ ++struct mali_bcast_unit *mali_bcast_unit_create(const _mali_osk_resource_t *resource); ++void mali_bcast_unit_delete(struct mali_bcast_unit *bcast_unit); ++ ++/* Add a group to the list of (MMU + PP) pairs broadcasts go out to. */ ++void mali_bcast_add_group(struct mali_bcast_unit *bcast_unit, struct mali_group *group); ++ ++/* Remove a group to the list of (MMU + PP) pairs broadcasts go out to. */ ++void mali_bcast_remove_group(struct mali_bcast_unit *bcast_unit, struct mali_group *group); ++ ++/* Re-set cached mask. This needs to be called after having been suspended. */ ++void mali_bcast_reset(struct mali_bcast_unit *bcast_unit); ++ ++/** ++ * Disable broadcast unit ++ * ++ * mali_bcast_enable must be called to re-enable the unit. Cores may not be ++ * added or removed when the unit is disabled. ++ */ ++void mali_bcast_disable(struct mali_bcast_unit *bcast_unit); ++ ++/** ++ * Re-enable broadcast unit ++ * ++ * This resets the masks to include the cores present when mali_bcast_disable was called. ++ */ ++MALI_STATIC_INLINE void mali_bcast_enable(struct mali_bcast_unit *bcast_unit) ++{ ++ mali_bcast_reset(bcast_unit); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.c +new file mode 100644 +index 0000000..0e41d93 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.c +@@ -0,0 +1,209 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_dlbu.h" ++#include "mali_memory.h" ++#include "mali_pp.h" ++#include "mali_group.h" ++#include "mali_osk.h" ++#include "mali_hw_core.h" ++ ++/** ++ * Size of DLBU registers in bytes ++ */ ++#define MALI_DLBU_SIZE 0x400 ++ ++u32 mali_dlbu_phys_addr = 0; ++static mali_io_address mali_dlbu_cpu_addr = 0; ++ ++/** ++ * DLBU register numbers ++ * Used in the register read/write routines. ++ * See the hardware documentation for more information about each register ++ */ ++typedef enum mali_dlbu_register { ++ MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR = 0x0000, /**< Master tile list physical base address; ++ 31:12 Physical address to the page used for the DLBU ++ 0 DLBU enable - set this bit to 1 enables the AXI bus ++ between PPs and L2s, setting to 0 disables the router and ++ no further transactions are sent to DLBU */ ++ MALI_DLBU_REGISTER_MASTER_TLLIST_VADDR = 0x0004, /**< Master tile list virtual base address; ++ 31:12 Virtual address to the page used for the DLBU */ ++ MALI_DLBU_REGISTER_TLLIST_VBASEADDR = 0x0008, /**< Tile list virtual base address; ++ 31:12 Virtual address to the tile list. This address is used when ++ calculating the call address sent to PP.*/ ++ MALI_DLBU_REGISTER_FB_DIM = 0x000C, /**< Framebuffer dimension; ++ 23:16 Number of tiles in Y direction-1 ++ 7:0 Number of tiles in X direction-1 */ ++ MALI_DLBU_REGISTER_TLLIST_CONF = 0x0010, /**< Tile list configuration; ++ 29:28 select the size of each allocated block: 0=128 bytes, 1=256, 2=512, 3=1024 ++ 21:16 2^n number of tiles to be binned to one tile list in Y direction ++ 5:0 2^n number of tiles to be binned to one tile list in X direction */ ++ MALI_DLBU_REGISTER_START_TILE_POS = 0x0014, /**< Start tile positions; ++ 31:24 start position in Y direction for group 1 ++ 23:16 start position in X direction for group 1 ++ 15:8 start position in Y direction for group 0 ++ 7:0 start position in X direction for group 0 */ ++ MALI_DLBU_REGISTER_PP_ENABLE_MASK = 0x0018, /**< PP enable mask; ++ 7 enable PP7 for load balancing ++ 6 enable PP6 for load balancing ++ 5 enable PP5 for load balancing ++ 4 enable PP4 for load balancing ++ 3 enable PP3 for load balancing ++ 2 enable PP2 for load balancing ++ 1 enable PP1 for load balancing ++ 0 enable PP0 for load balancing */ ++} mali_dlbu_register; ++ ++typedef enum { ++ PP0ENABLE = 0, ++ PP1ENABLE, ++ PP2ENABLE, ++ PP3ENABLE, ++ PP4ENABLE, ++ PP5ENABLE, ++ PP6ENABLE, ++ PP7ENABLE ++} mali_dlbu_pp_enable; ++ ++struct mali_dlbu_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ u32 pp_cores_mask; /**< This is a mask for the PP cores whose operation will be controlled by LBU ++ see MALI_DLBU_REGISTER_PP_ENABLE_MASK register */ ++}; ++ ++_mali_osk_errcode_t mali_dlbu_initialize(void) ++{ ++ ++ MALI_DEBUG_PRINT(2, ("Mali DLBU: Initializing\n")); ++ ++ if (_MALI_OSK_ERR_OK == mali_mmu_get_table_page(&mali_dlbu_phys_addr, &mali_dlbu_cpu_addr)) { ++ MALI_SUCCESS; ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++void mali_dlbu_terminate(void) ++{ ++ MALI_DEBUG_PRINT(3, ("Mali DLBU: terminating\n")); ++ ++ mali_mmu_release_table_page(mali_dlbu_phys_addr, mali_dlbu_cpu_addr); ++} ++ ++struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource) ++{ ++ struct mali_dlbu_core *core = NULL; ++ ++ MALI_DEBUG_PRINT(2, ("Mali DLBU: Creating Mali dynamic load balancing unit: %s\n", resource->description)); ++ ++ core = _mali_osk_malloc(sizeof(struct mali_dlbu_core)); ++ if (NULL != core) { ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI_DLBU_SIZE)) { ++ core->pp_cores_mask = 0; ++ if (_MALI_OSK_ERR_OK == mali_dlbu_reset(core)) { ++ return core; ++ } ++ MALI_PRINT_ERROR(("Failed to reset DLBU %s\n", core->hw_core.description)); ++ mali_hw_core_delete(&core->hw_core); ++ } ++ ++ _mali_osk_free(core); ++ } else { ++ MALI_PRINT_ERROR(("Mali DLBU: Failed to allocate memory for DLBU core\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_dlbu_delete(struct mali_dlbu_core *dlbu) ++{ ++ MALI_DEBUG_ASSERT_POINTER(dlbu); ++ ++ mali_dlbu_reset(dlbu); ++ mali_hw_core_delete(&dlbu->hw_core); ++ _mali_osk_free(dlbu); ++} ++ ++_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu) ++{ ++ u32 dlbu_registers[7]; ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ MALI_DEBUG_ASSERT_POINTER(dlbu); ++ ++ MALI_DEBUG_PRINT(4, ("Mali DLBU: mali_dlbu_reset: %s\n", dlbu->hw_core.description)); ++ ++ dlbu_registers[0] = mali_dlbu_phys_addr | 1; /* bit 0 enables the whole core */ ++ dlbu_registers[1] = MALI_DLBU_VIRT_ADDR; ++ dlbu_registers[2] = 0; ++ dlbu_registers[3] = 0; ++ dlbu_registers[4] = 0; ++ dlbu_registers[5] = 0; ++ dlbu_registers[6] = dlbu->pp_cores_mask; ++ ++ /* write reset values to core registers */ ++ mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_MASTER_TLLIST_PHYS_ADDR, dlbu_registers, 7); ++ ++ err = _MALI_OSK_ERR_OK; ++ ++ return err; ++} ++ ++void mali_dlbu_update_mask(struct mali_dlbu_core *dlbu) ++{ ++ MALI_DEBUG_ASSERT_POINTER(dlbu); ++ ++ mali_hw_core_register_write(&dlbu->hw_core, MALI_DLBU_REGISTER_PP_ENABLE_MASK, dlbu->pp_cores_mask); ++} ++ ++void mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group) ++{ ++ struct mali_pp_core *pp_core; ++ u32 bcast_id; ++ ++ MALI_DEBUG_ASSERT_POINTER( dlbu ); ++ MALI_DEBUG_ASSERT_POINTER( group ); ++ ++ pp_core = mali_group_get_pp_core(group); ++ bcast_id = mali_pp_core_get_bcast_id(pp_core); ++ ++ dlbu->pp_cores_mask |= bcast_id; ++ MALI_DEBUG_PRINT(3, ("Mali DLBU: Adding core[%d] New mask= 0x%02x\n", bcast_id , dlbu->pp_cores_mask)); ++} ++ ++/* Remove a group from the DLBU */ ++void mali_dlbu_remove_group(struct mali_dlbu_core *dlbu, struct mali_group *group) ++{ ++ struct mali_pp_core *pp_core; ++ u32 bcast_id; ++ ++ MALI_DEBUG_ASSERT_POINTER( dlbu ); ++ MALI_DEBUG_ASSERT_POINTER( group ); ++ ++ pp_core = mali_group_get_pp_core(group); ++ bcast_id = mali_pp_core_get_bcast_id(pp_core); ++ ++ dlbu->pp_cores_mask &= ~bcast_id; ++ MALI_DEBUG_PRINT(3, ("Mali DLBU: Removing core[%d] New mask= 0x%02x\n", bcast_id, dlbu->pp_cores_mask)); ++} ++ ++/* Configure the DLBU for \a job. This needs to be done before the job is started on the groups in the DLBU. */ ++void mali_dlbu_config_job(struct mali_dlbu_core *dlbu, struct mali_pp_job *job) ++{ ++ u32 *registers; ++ MALI_DEBUG_ASSERT(job); ++ registers = mali_pp_job_get_dlbu_registers(job); ++ MALI_DEBUG_PRINT(4, ("Mali DLBU: Starting job\n")); ++ ++ /* Writing 4 registers: ++ * DLBU registers except the first two (written once at DLBU initialisation / reset) and the PP_ENABLE_MASK register */ ++ mali_hw_core_register_write_array_relaxed(&dlbu->hw_core, MALI_DLBU_REGISTER_TLLIST_VBASEADDR, registers, 4); ++ ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.h +new file mode 100644 +index 0000000..8fbfc35 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dlbu.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_DLBU_H__ ++#define __MALI_DLBU_H__ ++ ++#define MALI_DLBU_VIRT_ADDR 0xFFF00000 /* master tile virtual address fixed at this value and mapped into every session */ ++ ++#include "mali_osk.h" ++ ++struct mali_pp_job; ++struct mali_group; ++ ++extern u32 mali_dlbu_phys_addr; ++ ++struct mali_dlbu_core; ++ ++_mali_osk_errcode_t mali_dlbu_initialize(void); ++void mali_dlbu_terminate(void); ++ ++struct mali_dlbu_core *mali_dlbu_create(const _mali_osk_resource_t * resource); ++void mali_dlbu_delete(struct mali_dlbu_core *dlbu); ++ ++_mali_osk_errcode_t mali_dlbu_reset(struct mali_dlbu_core *dlbu); ++ ++void mali_dlbu_add_group(struct mali_dlbu_core *dlbu, struct mali_group *group); ++void mali_dlbu_remove_group(struct mali_dlbu_core *dlbu, struct mali_group *group); ++ ++/** @brief Called to update HW after DLBU state changed ++ * ++ * This function must be called after \a mali_dlbu_add_group or \a ++ * mali_dlbu_remove_group to write the updated mask to hardware, unless the ++ * same is accomplished by calling \a mali_dlbu_reset. ++ */ ++void mali_dlbu_update_mask(struct mali_dlbu_core *dlbu); ++ ++void mali_dlbu_config_job(struct mali_dlbu_core *dlbu, struct mali_pp_job *job); ++ ++#endif /* __MALI_DLBU_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.c +new file mode 100644 +index 0000000..a529626 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.c +@@ -0,0 +1,201 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_hw_core.h" ++#include "mali_dma.h" ++ ++/** ++ * Size of the Mali-450 DMA unit registers in bytes. ++ */ ++#define MALI450_DMA_REG_SIZE 0x08 ++ ++/** ++ * Value that appears in MEMSIZE if an error occurs when reading the command list. ++ */ ++#define MALI450_DMA_BUS_ERR_VAL 0xffffffff ++ ++/** ++ * Mali DMA registers ++ * Used in the register read/write routines. ++ * See the hardware documentation for more information about each register. ++ */ ++typedef enum mali_dma_register { ++ ++ MALI450_DMA_REG_SOURCE_ADDRESS = 0x0000, ++ MALI450_DMA_REG_SOURCE_SIZE = 0x0004, ++} mali_dma_register; ++ ++struct mali_dma_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ _mali_osk_spinlock_t *lock; /**< Lock protecting access to DMA core */ ++ mali_dma_pool pool; /**< Memory pool for command buffers */ ++}; ++ ++static struct mali_dma_core *mali_global_dma_core = NULL; ++ ++struct mali_dma_core *mali_dma_create(_mali_osk_resource_t *resource) ++{ ++ struct mali_dma_core* dma; ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT(NULL == mali_global_dma_core); ++ ++ dma = _mali_osk_malloc(sizeof(struct mali_dma_core)); ++ if (dma == NULL) goto alloc_failed; ++ ++ dma->lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_DMA_COMMAND); ++ if (NULL == dma->lock) goto lock_init_failed; ++ ++ dma->pool = mali_dma_pool_create(MALI_DMA_CMD_BUF_SIZE, 4, 0); ++ if (NULL == dma->pool) goto dma_pool_failed; ++ ++ err = mali_hw_core_create(&dma->hw_core, resource, MALI450_DMA_REG_SIZE); ++ if (_MALI_OSK_ERR_OK != err) goto hw_core_failed; ++ ++ mali_global_dma_core = dma; ++ MALI_DEBUG_PRINT(2, ("Mali DMA: Created Mali APB DMA unit\n")); ++ return dma; ++ ++ /* Error handling */ ++ ++hw_core_failed: ++ mali_dma_pool_destroy(dma->pool); ++dma_pool_failed: ++ _mali_osk_spinlock_term(dma->lock); ++lock_init_failed: ++ _mali_osk_free(dma); ++alloc_failed: ++ MALI_DEBUG_PRINT(2, ("Mali DMA: Failed to create APB DMA unit\n")); ++ return NULL; ++} ++ ++void mali_dma_delete(struct mali_dma_core *dma) ++{ ++ MALI_DEBUG_ASSERT_POINTER(dma); ++ ++ MALI_DEBUG_PRINT(2, ("Mali DMA: Deleted Mali APB DMA unit\n")); ++ ++ mali_hw_core_delete(&dma->hw_core); ++ _mali_osk_spinlock_term(dma->lock); ++ mali_dma_pool_destroy(dma->pool); ++ _mali_osk_free(dma); ++} ++ ++static void mali_dma_bus_error(struct mali_dma_core *dma) ++{ ++ u32 addr = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS); ++ ++ MALI_PRINT_ERROR(("Mali DMA: Bus error when reading command list from 0x%lx\n", addr)); ++ ++ /* Clear the bus error */ ++ mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, 0); ++} ++ ++static mali_bool mali_dma_is_busy(struct mali_dma_core *dma) ++{ ++ u32 val; ++ mali_bool dma_busy_flag = MALI_FALSE; ++ ++ MALI_DEBUG_ASSERT_POINTER(dma); ++ ++ val = mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE); ++ ++ if (MALI450_DMA_BUS_ERR_VAL == val) { ++ /* Bus error reading command list */ ++ mali_dma_bus_error(dma); ++ return MALI_FALSE; ++ } ++ if (val > 0) { ++ dma_busy_flag = MALI_TRUE; ++ } ++ ++ return dma_busy_flag; ++} ++ ++static void mali_dma_start_transfer(struct mali_dma_core* dma, mali_dma_cmd_buf *buf) ++{ ++ u32 memsize = buf->size * 4; ++ u32 addr = buf->phys_addr; ++ ++ MALI_DEBUG_ASSERT_POINTER(dma); ++ MALI_DEBUG_ASSERT(memsize < (1 << 16)); ++ MALI_DEBUG_ASSERT(0 == (memsize & 0x3)); /* 4 byte aligned */ ++ ++ MALI_DEBUG_ASSERT(!mali_dma_is_busy(dma)); ++ ++ /* Writes the physical source memory address of chunk containing command headers and data */ ++ mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS, addr); ++ ++ /* Writes the length of transfer */ ++ mali_hw_core_register_write(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE, memsize); ++} ++ ++_mali_osk_errcode_t mali_dma_get_cmd_buf(mali_dma_cmd_buf *buf) ++{ ++ MALI_DEBUG_ASSERT_POINTER(buf); ++ ++ buf->virt_addr = (u32*)mali_dma_pool_alloc(mali_global_dma_core->pool, &buf->phys_addr); ++ if (NULL == buf->virt_addr) { ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ /* size contains the number of words in the buffer and is incremented ++ * as commands are added to the buffer. */ ++ buf->size = 0; ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_dma_put_cmd_buf(mali_dma_cmd_buf *buf) ++{ ++ MALI_DEBUG_ASSERT_POINTER(buf); ++ ++ if (NULL == buf->virt_addr) return; ++ ++ mali_dma_pool_free(mali_global_dma_core->pool, buf->virt_addr, buf->phys_addr); ++ ++ buf->virt_addr = NULL; ++} ++ ++_mali_osk_errcode_t mali_dma_start(struct mali_dma_core* dma, mali_dma_cmd_buf *buf) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; ++ ++ _mali_osk_spinlock_lock(dma->lock); ++ ++ if (mali_dma_is_busy(dma)) { ++ err = _MALI_OSK_ERR_BUSY; ++ goto out; ++ } ++ ++ mali_dma_start_transfer(dma, buf); ++ ++out: ++ _mali_osk_spinlock_unlock(dma->lock); ++ return err; ++} ++ ++void mali_dma_debug(struct mali_dma_core *dma) ++{ ++ MALI_DEBUG_ASSERT_POINTER(dma); ++ MALI_DEBUG_PRINT(1, ("DMA unit registers:\n\t%08x, %08x\n", ++ mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_ADDRESS), ++ mali_hw_core_register_read(&dma->hw_core, MALI450_DMA_REG_SOURCE_SIZE) ++ )); ++ ++} ++ ++struct mali_dma_core *mali_dma_get_global_dma_core(void) ++{ ++ /* Returns the global dma core object */ ++ return mali_global_dma_core; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.h +new file mode 100644 +index 0000000..93b9ca0 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_dma.h +@@ -0,0 +1,190 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_DMA_H__ ++#define __MALI_DMA_H__ ++ ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_hw_core.h" ++ ++#define MALI_DMA_CMD_BUF_SIZE 1024 ++ ++typedef struct mali_dma_cmd_buf { ++ u32 *virt_addr; /**< CPU address of command buffer */ ++ u32 phys_addr; /**< Physical address of command buffer */ ++ u32 size; /**< Number of prepared words in command buffer */ ++} mali_dma_cmd_buf; ++ ++/** @brief Create a new DMA unit ++ * ++ * This is called from entry point of the driver in order to create and ++ * intialize the DMA resource ++ * ++ * @param resource it will be a pointer to a DMA resource ++ * @return DMA object on success, NULL on failure ++ */ ++struct mali_dma_core *mali_dma_create(_mali_osk_resource_t *resource); ++ ++/** @brief Delete DMA unit ++ * ++ * This is called on entry point of driver if the driver initialization fails ++ * after initialization of the DMA unit. It is also called on the exit of the ++ * driver to delete the DMA resource ++ * ++ * @param dma Pointer to DMA unit object ++ */ ++void mali_dma_delete(struct mali_dma_core *dma); ++ ++/** @brief Retrieves the MALI DMA core object (if there is) ++ * ++ * @return The Mali DMA object otherwise NULL ++ */ ++struct mali_dma_core *mali_dma_get_global_dma_core(void); ++ ++/** ++ * @brief Run a command buffer on the DMA unit ++ * ++ * @param dma Pointer to the DMA unit to use ++ * @param buf Pointer to the command buffer to use ++ * @return _MALI_OSK_ERR_OK if the buffer was started successfully, ++ * _MALI_OSK_ERR_BUSY if the DMA unit is busy. ++ */ ++_mali_osk_errcode_t mali_dma_start(struct mali_dma_core* dma, mali_dma_cmd_buf *buf); ++ ++/** ++ * @brief Create a DMA command ++ * ++ * @param core Mali core ++ * @param reg offset to register of core ++ * @param n number of registers to write ++ */ ++MALI_STATIC_INLINE u32 mali_dma_command_write(struct mali_hw_core *core, u32 reg, u32 n) ++{ ++ u32 core_offset = core->phys_offset; ++ ++ MALI_DEBUG_ASSERT(reg < 0x2000); ++ MALI_DEBUG_ASSERT(n < 0x800); ++ MALI_DEBUG_ASSERT(core_offset < 0x30000); ++ MALI_DEBUG_ASSERT(0 == ((core_offset + reg) & ~0x7FFFF)); ++ ++ return (n << 20) | (core_offset + reg); ++} ++ ++/** ++ * @brief Add a array write to DMA command buffer ++ * ++ * @param buf DMA command buffer to fill in ++ * @param core Core to do DMA to ++ * @param reg Register on core to start writing to ++ * @param data Pointer to data to write ++ * @param count Number of 4 byte words to write ++ */ ++MALI_STATIC_INLINE void mali_dma_write_array(mali_dma_cmd_buf *buf, struct mali_hw_core *core, ++ u32 reg, u32 *data, u32 count) ++{ ++ MALI_DEBUG_ASSERT((buf->size + 1 + count ) < MALI_DMA_CMD_BUF_SIZE / 4); ++ ++ buf->virt_addr[buf->size++] = mali_dma_command_write(core, reg, count); ++ ++ _mali_osk_memcpy(buf->virt_addr + buf->size, data, count * sizeof(*buf->virt_addr)); ++ ++ buf->size += count; ++} ++ ++/** ++ * @brief Add a conditional array write to DMA command buffer ++ * ++ * @param buf DMA command buffer to fill in ++ * @param core Core to do DMA to ++ * @param reg Register on core to start writing to ++ * @param data Pointer to data to write ++ * @param count Number of 4 byte words to write ++ * @param ref Pointer to referance data that can be skipped if equal ++ */ ++MALI_STATIC_INLINE void mali_dma_write_array_conditional(mali_dma_cmd_buf *buf, struct mali_hw_core *core, ++ u32 reg, u32 *data, u32 count, const u32 *ref) ++{ ++ /* Do conditional array writes are not yet implemented, fallback to a ++ * normal array write. */ ++ mali_dma_write_array(buf, core, reg, data, count); ++} ++ ++/** ++ * @brief Add a conditional register write to the DMA command buffer ++ * ++ * If the data matches the reference the command will be skipped. ++ * ++ * @param buf DMA command buffer to fill in ++ * @param core Core to do DMA to ++ * @param reg Register on core to start writing to ++ * @param data Pointer to data to write ++ * @param ref Pointer to referance data that can be skipped if equal ++ */ ++MALI_STATIC_INLINE void mali_dma_write_conditional(mali_dma_cmd_buf *buf, struct mali_hw_core *core, ++ u32 reg, u32 data, const u32 ref) ++{ ++ /* Skip write if reference value is equal to data. */ ++ if (data == ref) return; ++ ++ buf->virt_addr[buf->size++] = mali_dma_command_write(core, reg, 1); ++ ++ buf->virt_addr[buf->size++] = data; ++ ++ MALI_DEBUG_ASSERT(buf->size < MALI_DMA_CMD_BUF_SIZE / 4); ++} ++ ++/** ++ * @brief Add a register write to the DMA command buffer ++ * ++ * @param buf DMA command buffer to fill in ++ * @param core Core to do DMA to ++ * @param reg Register on core to start writing to ++ * @param data Pointer to data to write ++ */ ++MALI_STATIC_INLINE void mali_dma_write(mali_dma_cmd_buf *buf, struct mali_hw_core *core, ++ u32 reg, u32 data) ++{ ++ buf->virt_addr[buf->size++] = mali_dma_command_write(core, reg, 1); ++ ++ buf->virt_addr[buf->size++] = data; ++ ++ MALI_DEBUG_ASSERT(buf->size < MALI_DMA_CMD_BUF_SIZE / 4); ++} ++ ++/** ++ * @brief Prepare DMA command buffer for use ++ * ++ * This function allocates the DMA buffer itself. ++ * ++ * @param buf The mali_dma_cmd_buf to prepare ++ * @return _MALI_OSK_ERR_OK if the \a buf is ready to use ++ */ ++_mali_osk_errcode_t mali_dma_get_cmd_buf(mali_dma_cmd_buf *buf); ++ ++/** ++ * @brief Check if a DMA command buffer is ready for use ++ * ++ * @param buf The mali_dma_cmd_buf to check ++ * @return MALI_TRUE if buffer is usable, MALI_FALSE otherwise ++ */ ++MALI_STATIC_INLINE mali_bool mali_dma_cmd_buf_is_valid(mali_dma_cmd_buf *buf) ++{ ++ return NULL != buf->virt_addr; ++} ++ ++/** ++ * @brief Return a DMA command buffer ++ * ++ * @param buf Pointer to DMA command buffer to return ++ */ ++void mali_dma_put_cmd_buf(mali_dma_cmd_buf *buf); ++ ++#endif /* __MALI_DMA_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.c +new file mode 100644 +index 0000000..a3982b8 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.c +@@ -0,0 +1,337 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_gp.h" ++#include "mali_hw_core.h" ++#include "mali_group.h" ++#include "mali_osk.h" ++#include "regs/mali_gp_regs.h" ++#include "mali_kernel_common.h" ++#include "mali_kernel_core.h" ++#if defined(CONFIG_MALI400_PROFILING) ++#include "mali_osk_profiling.h" ++#endif ++ ++static struct mali_gp_core *mali_global_gp_core = NULL; ++ ++/* Interrupt handlers */ ++static void mali_gp_irq_probe_trigger(void *data); ++static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data); ++ ++struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group) ++{ ++ struct mali_gp_core* core = NULL; ++ ++ MALI_DEBUG_ASSERT(NULL == mali_global_gp_core); ++ MALI_DEBUG_PRINT(2, ("Mali GP: Creating Mali GP core: %s\n", resource->description)); ++ ++ core = _mali_osk_malloc(sizeof(struct mali_gp_core)); ++ if (NULL != core) { ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALIGP2_REGISTER_ADDRESS_SPACE_SIZE)) { ++ _mali_osk_errcode_t ret; ++ ++ ret = mali_gp_reset(core); ++ ++ if (_MALI_OSK_ERR_OK == ret) { ++ ret = mali_group_add_gp_core(group, core); ++ if (_MALI_OSK_ERR_OK == ret) { ++ /* Setup IRQ handlers (which will do IRQ probing if needed) */ ++ core->irq = _mali_osk_irq_init(resource->irq, ++ mali_group_upper_half_gp, ++ group, ++ mali_gp_irq_probe_trigger, ++ mali_gp_irq_probe_ack, ++ core, ++ resource->description); ++ if (NULL != core->irq) { ++ MALI_DEBUG_PRINT(4, ("Mali GP: set global gp core from 0x%08X to 0x%08X\n", mali_global_gp_core, core)); ++ mali_global_gp_core = core; ++ ++ return core; ++ } else { ++ MALI_PRINT_ERROR(("Mali GP: Failed to setup interrupt handlers for GP core %s\n", core->hw_core.description)); ++ } ++ mali_group_remove_gp_core(group); ++ } else { ++ MALI_PRINT_ERROR(("Mali GP: Failed to add core %s to group\n", core->hw_core.description)); ++ } ++ } ++ mali_hw_core_delete(&core->hw_core); ++ } ++ ++ _mali_osk_free(core); ++ } else { ++ MALI_PRINT_ERROR(("Failed to allocate memory for GP core\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_gp_delete(struct mali_gp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ _mali_osk_irq_term(core->irq); ++ mali_hw_core_delete(&core->hw_core); ++ mali_global_gp_core = NULL; ++ _mali_osk_free(core); ++} ++ ++void mali_gp_stop_bus(struct mali_gp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_STOP_BUS); ++} ++ ++_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core) ++{ ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ /* Send the stop bus command. */ ++ mali_gp_stop_bus(core); ++ ++ /* Wait for bus to be stopped */ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ if (mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS) & MALIGP2_REG_VAL_STATUS_BUS_STOPPED) { ++ break; ++ } ++ } ++ ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Mali GP: Failed to stop bus on %s\n", core->hw_core.description)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_gp_hard_reset(struct mali_gp_core *core) ++{ ++ const u32 reset_wait_target_register = MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW; ++ const u32 reset_invalid_value = 0xC0FFE000; ++ const u32 reset_check_value = 0xC01A0000; ++ const u32 reset_default_value = 0; ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ MALI_DEBUG_PRINT(4, ("Mali GP: Hard reset of core %s\n", core->hw_core.description)); ++ ++ mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_invalid_value); ++ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_RESET); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_check_value); ++ if (reset_check_value == mali_hw_core_register_read(&core->hw_core, reset_wait_target_register)) { ++ break; ++ } ++ } ++ ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Mali GP: The hard reset loop didn't work, unable to recover\n")); ++ } ++ ++ mali_hw_core_register_write(&core->hw_core, reset_wait_target_register, reset_default_value); /* set it back to the default */ ++ /* Re-enable interrupts */ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); ++ ++} ++ ++void mali_gp_reset_async(struct mali_gp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ MALI_DEBUG_PRINT(4, ("Mali GP: Reset of core %s\n", core->hw_core.description)); ++ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALI400GP_REG_VAL_IRQ_RESET_COMPLETED); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALI400GP_REG_VAL_CMD_SOFT_RESET); ++ ++} ++ ++_mali_osk_errcode_t mali_gp_reset_wait(struct mali_gp_core *core) ++{ ++ int i; ++ u32 rawstat = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ rawstat = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT); ++ if (rawstat & MALI400GP_REG_VAL_IRQ_RESET_COMPLETED) { ++ break; ++ } ++ } ++ ++ if (i == MALI_REG_POLL_COUNT_FAST) { ++ MALI_PRINT_ERROR(("Mali GP: Failed to reset core %s, rawstat: 0x%08x\n", ++ core->hw_core.description, rawstat)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Re-enable interrupts */ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_MASK_ALL); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core) ++{ ++ mali_gp_reset_async(core); ++ return mali_gp_reset_wait(core); ++} ++ ++void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job) ++{ ++ u32 startcmd = 0; ++ u32 *frame_registers = mali_gp_job_get_frame_registers(job); ++ u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job); ++ u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job); ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ if (mali_gp_job_has_vs_job(job)) { ++ startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_VS; ++ } ++ ++ if (mali_gp_job_has_plbu_job(job)) { ++ startcmd |= (u32) MALIGP2_REG_VAL_CMD_START_PLBU; ++ } ++ ++ MALI_DEBUG_ASSERT(0 != startcmd); ++ ++ mali_hw_core_register_write_array_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR, frame_registers, MALIGP2_NUM_REGS_FRAME); ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src0) { ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC, counter_src0); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); ++ } ++ if (MALI_HW_CORE_NO_COUNTER != counter_src1) { ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC, counter_src1); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALIGP2_REG_VAL_PERF_CNT_ENABLE); ++ } ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP: Starting job (0x%08x) on core %s with command 0x%08X\n", job, core->hw_core.description, startcmd)); ++ ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); ++ ++ /* Barrier to make sure the previous register write is finished */ ++ _mali_osk_write_mem_barrier(); ++ ++ /* This is the command that starts the core. */ ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, startcmd); ++ ++ /* Barrier to make sure the previous register write is finished */ ++ _mali_osk_write_mem_barrier(); ++} ++ ++void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr) ++{ ++ u32 irq_readout; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT); ++ ++ if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) { ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, (MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | MALIGP2_REG_VAL_IRQ_HANG)); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); /* re-enable interrupts */ ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR, start_addr); ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR, end_addr); ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP: Resuming job\n")); ++ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_CMD, MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC); ++ _mali_osk_write_mem_barrier(); ++ } ++ /* ++ * else: core has been reset between PLBU_OUT_OF_MEM interrupt and this new heap response. ++ * A timeout or a page fault on Mali-200 PP core can cause this behaviour. ++ */ ++} ++ ++u32 mali_gp_core_get_version(struct mali_gp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_VERSION); ++} ++ ++struct mali_gp_core *mali_gp_get_global_gp_core(void) ++{ ++ return mali_global_gp_core; ++} ++ ++/* ------------- interrupt handling below ------------------ */ ++static void mali_gp_irq_probe_trigger(void *data) ++{ ++ struct mali_gp_core *core = (struct mali_gp_core *)data; ++ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_USED); ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT, MALIGP2_REG_VAL_CMD_FORCE_HANG); ++ _mali_osk_mem_barrier(); ++} ++ ++static _mali_osk_errcode_t mali_gp_irq_probe_ack(void *data) ++{ ++ struct mali_gp_core *core = (struct mali_gp_core *)data; ++ u32 irq_readout; ++ ++ irq_readout = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); ++ if (MALIGP2_REG_VAL_IRQ_FORCE_HANG & irq_readout) { ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, MALIGP2_REG_VAL_IRQ_FORCE_HANG); ++ _mali_osk_mem_barrier(); ++ return _MALI_OSK_ERR_OK; ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++/* ------ local helper functions below --------- */ ++#if MALI_STATE_TRACKING ++u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size) ++{ ++ int n = 0; ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "\tGP: %s\n", core->hw_core.description); ++ ++ return n; ++} ++#endif ++ ++void mali_gp_update_performance_counters(struct mali_gp_core *core, struct mali_gp_job *job, mali_bool suspend) ++{ ++ u32 val0 = 0; ++ u32 val1 = 0; ++ u32 counter_src0 = mali_gp_job_get_perf_counter_src0(job); ++ u32 counter_src1 = mali_gp_job_get_perf_counter_src1(job); ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src0) { ++ val0 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE); ++ mali_gp_job_set_perf_counter_value0(job, val0); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C0, val0); ++#endif ++ ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src1) { ++ val1 = mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE); ++ mali_gp_job_set_perf_counter_value1(job, val1); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_report_hw_counter(COUNTER_VP_0_C1, val1); ++#endif ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.h +new file mode 100644 +index 0000000..5450c56 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp.h +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_GP_H__ ++#define __MALI_GP_H__ ++ ++#include "mali_osk.h" ++#include "mali_gp_job.h" ++#include "mali_hw_core.h" ++#include "regs/mali_gp_regs.h" ++ ++struct mali_group; ++ ++/** ++ * Definition of the GP core struct ++ * Used to track a GP core in the system. ++ */ ++struct mali_gp_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ _mali_osk_irq_t *irq; /**< IRQ handler */ ++}; ++ ++_mali_osk_errcode_t mali_gp_initialize(void); ++void mali_gp_terminate(void); ++ ++struct mali_gp_core *mali_gp_create(const _mali_osk_resource_t * resource, struct mali_group *group); ++void mali_gp_delete(struct mali_gp_core *core); ++ ++void mali_gp_stop_bus(struct mali_gp_core *core); ++_mali_osk_errcode_t mali_gp_stop_bus_wait(struct mali_gp_core *core); ++void mali_gp_reset_async(struct mali_gp_core *core); ++_mali_osk_errcode_t mali_gp_reset_wait(struct mali_gp_core *core); ++void mali_gp_hard_reset(struct mali_gp_core *core); ++_mali_osk_errcode_t mali_gp_reset(struct mali_gp_core *core); ++ ++void mali_gp_job_start(struct mali_gp_core *core, struct mali_gp_job *job); ++void mali_gp_resume_with_new_heap(struct mali_gp_core *core, u32 start_addr, u32 end_addr); ++ ++u32 mali_gp_core_get_version(struct mali_gp_core *core); ++ ++struct mali_gp_core *mali_gp_get_global_gp_core(void); ++ ++u32 mali_gp_dump_state(struct mali_gp_core *core, char *buf, u32 size); ++ ++void mali_gp_update_performance_counters(struct mali_gp_core *core, struct mali_gp_job *job, mali_bool suspend); ++ ++/*** Accessor functions ***/ ++MALI_STATIC_INLINE const char *mali_gp_get_hw_core_desc(struct mali_gp_core *core) ++{ ++ return core->hw_core.description; ++} ++ ++/*** Register reading/writing functions ***/ ++MALI_STATIC_INLINE u32 mali_gp_get_int_stat(struct mali_gp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_STAT); ++} ++ ++MALI_STATIC_INLINE void mali_gp_mask_all_interrupts(struct mali_gp_core *core) ++{ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_VAL_IRQ_MASK_NONE); ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_read_rawstat(struct mali_gp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT) & MALIGP2_REG_VAL_IRQ_MASK_USED; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_read_core_status(struct mali_gp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_STATUS); ++} ++ ++MALI_STATIC_INLINE void mali_gp_enable_interrupts(struct mali_gp_core *core, u32 irq_exceptions) ++{ ++ /* Enable all interrupts, except those specified in irq_exceptions */ ++ mali_hw_core_register_write(&core->hw_core, MALIGP2_REG_ADDR_MGMT_INT_MASK, ++ MALIGP2_REG_VAL_IRQ_MASK_USED & ~irq_exceptions); ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_read_plbu_alloc_start_addr(struct mali_gp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR); ++} ++ ++#endif /* __MALI_GP_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.c +new file mode 100644 +index 0000000..a966f57 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.c +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_gp_job.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_uk_types.h" ++ ++static u32 gp_counter_src0 = MALI_HW_CORE_NO_COUNTER; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ ++static u32 gp_counter_src1 = MALI_HW_CORE_NO_COUNTER; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ ++ ++struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *uargs, u32 id, struct mali_timeline_tracker *pp_tracker) ++{ ++ struct mali_gp_job *job; ++ u32 perf_counter_flag; ++ ++ job = _mali_osk_malloc(sizeof(struct mali_gp_job)); ++ if (NULL != job) { ++ job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_FINISHED, sizeof(_mali_uk_gp_job_finished_s)); ++ if (NULL == job->finished_notification) { ++ _mali_osk_free(job); ++ return NULL; ++ } ++ ++ job->oom_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s)); ++ if (NULL == job->oom_notification) { ++ _mali_osk_notification_delete(job->finished_notification); ++ _mali_osk_free(job); ++ return NULL; ++ } ++ ++ if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_gp_start_job_s))) { ++ _mali_osk_notification_delete(job->finished_notification); ++ _mali_osk_notification_delete(job->oom_notification); ++ _mali_osk_free(job); ++ return NULL; ++ } ++ ++ perf_counter_flag = mali_gp_job_get_perf_counter_flag(job); ++ ++ /* case when no counters came from user space ++ * so pass the debugfs / DS-5 provided global ones to the job object */ ++ if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) || ++ (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE))) { ++ mali_gp_job_set_perf_counter_src0(job, mali_gp_job_get_gp_counter_src0()); ++ mali_gp_job_set_perf_counter_src1(job, mali_gp_job_get_gp_counter_src1()); ++ } ++ ++ _mali_osk_list_init(&job->list); ++ job->session = session; ++ job->id = id; ++ job->heap_current_addr = job->uargs.frame_registers[4]; ++ job->perf_counter_value0 = 0; ++ job->perf_counter_value1 = 0; ++ job->pid = _mali_osk_get_pid(); ++ job->tid = _mali_osk_get_tid(); ++ ++ job->pp_tracker = pp_tracker; ++ if (NULL != job->pp_tracker) { ++ /* Take a reference on PP job's tracker that will be released when the GP ++ job is done. */ ++ mali_timeline_system_tracker_get(session->timeline_system, pp_tracker); ++ } ++ ++ mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_GP, NULL, job); ++ mali_timeline_fence_copy_uk_fence(&(job->tracker.fence), &(job->uargs.fence)); ++ ++ return job; ++ } ++ ++ return NULL; ++} ++ ++void mali_gp_job_delete(struct mali_gp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT(NULL == job->pp_tracker); ++ ++ /* de-allocate the pre-allocated oom notifications */ ++ if (NULL != job->oom_notification) { ++ _mali_osk_notification_delete(job->oom_notification); ++ job->oom_notification = NULL; ++ } ++ if (NULL != job->finished_notification) { ++ _mali_osk_notification_delete(job->finished_notification); ++ job->finished_notification = NULL; ++ } ++ ++ _mali_osk_free(job); ++} ++ ++u32 mali_gp_job_get_gp_counter_src0(void) ++{ ++ return gp_counter_src0; ++} ++ ++void mali_gp_job_set_gp_counter_src0(u32 counter) ++{ ++ gp_counter_src0 = counter; ++} ++ ++u32 mali_gp_job_get_gp_counter_src1(void) ++{ ++ return gp_counter_src1; ++} ++ ++void mali_gp_job_set_gp_counter_src1(u32 counter) ++{ ++ gp_counter_src1 = counter; ++} ++ ++mali_scheduler_mask mali_gp_job_signal_pp_tracker(struct mali_gp_job *job, mali_bool success) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ if (NULL != job->pp_tracker) { ++ schedule_mask |= mali_timeline_system_tracker_put(job->session->timeline_system, job->pp_tracker, MALI_FALSE == success); ++ job->pp_tracker = NULL; ++ } ++ ++ return schedule_mask; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.h +new file mode 100644 +index 0000000..1813c9d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_job.h +@@ -0,0 +1,186 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_GP_JOB_H__ ++#define __MALI_GP_JOB_H__ ++ ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_uk_types.h" ++#include "mali_session.h" ++#include "mali_timeline.h" ++#include "mali_scheduler_types.h" ++ ++/** ++ * The structure represents a GP job, including all sub-jobs ++ * (This struct unfortunately needs to be public because of how the _mali_osk_list_* ++ * mechanism works) ++ */ ++struct mali_gp_job { ++ _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ ++ struct mali_session_data *session; /**< Session which submitted this job */ ++ _mali_uk_gp_start_job_s uargs; /**< Arguments from user space */ ++ u32 id; /**< Identifier for this job in kernel space (sequential numbering) */ ++ u32 cache_order; /**< Cache order used for L2 cache flushing (sequential numbering) */ ++ u32 heap_current_addr; /**< Holds the current HEAP address when the job has completed */ ++ u32 perf_counter_value0; /**< Value of performance counter 0 (to be returned to user space) */ ++ u32 perf_counter_value1; /**< Value of performance counter 1 (to be returned to user space) */ ++ u32 pid; /**< Process ID of submitting process */ ++ u32 tid; /**< Thread ID of submitting thread */ ++ _mali_osk_notification_t *finished_notification; /**< Notification sent back to userspace on job complete */ ++ _mali_osk_notification_t *oom_notification; /**< Notification sent back to userspace on OOM */ ++ struct mali_timeline_tracker tracker; /**< Timeline tracker for this job */ ++ struct mali_timeline_tracker *pp_tracker; /**< Pointer to Timeline tracker for PP job that depends on this job. */ ++}; ++ ++struct mali_gp_job *mali_gp_job_create(struct mali_session_data *session, _mali_uk_gp_start_job_s *uargs, u32 id, struct mali_timeline_tracker *pp_tracker); ++void mali_gp_job_delete(struct mali_gp_job *job); ++ ++u32 mali_gp_job_get_gp_counter_src0(void); ++void mali_gp_job_set_gp_counter_src0(u32 counter); ++u32 mali_gp_job_get_gp_counter_src1(void); ++void mali_gp_job_set_gp_counter_src1(u32 counter); ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_id(struct mali_gp_job *job) ++{ ++ return (NULL == job) ? 0 : job->id; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_cache_order(struct mali_gp_job *job) ++{ ++ return (NULL == job) ? 0 : job->cache_order; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_user_id(struct mali_gp_job *job) ++{ ++ return job->uargs.user_job_ptr; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_frame_builder_id(struct mali_gp_job *job) ++{ ++ return job->uargs.frame_builder_id; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_flush_id(struct mali_gp_job *job) ++{ ++ return job->uargs.flush_id; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_pid(struct mali_gp_job *job) ++{ ++ return job->pid; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_tid(struct mali_gp_job *job) ++{ ++ return job->tid; ++} ++ ++MALI_STATIC_INLINE u32* mali_gp_job_get_frame_registers(struct mali_gp_job *job) ++{ ++ return job->uargs.frame_registers; ++} ++ ++MALI_STATIC_INLINE struct mali_session_data *mali_gp_job_get_session(struct mali_gp_job *job) ++{ ++ return job->session; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_gp_job_has_vs_job(struct mali_gp_job *job) ++{ ++ return (job->uargs.frame_registers[0] != job->uargs.frame_registers[1]) ? MALI_TRUE : MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_gp_job_has_plbu_job(struct mali_gp_job *job) ++{ ++ return (job->uargs.frame_registers[2] != job->uargs.frame_registers[3]) ? MALI_TRUE : MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_current_heap_addr(struct mali_gp_job *job) ++{ ++ return job->heap_current_addr; ++} ++ ++MALI_STATIC_INLINE void mali_gp_job_set_current_heap_addr(struct mali_gp_job *job, u32 heap_addr) ++{ ++ job->heap_current_addr = heap_addr; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_flag(struct mali_gp_job *job) ++{ ++ return job->uargs.perf_counter_flag; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src0(struct mali_gp_job *job) ++{ ++ return job->uargs.perf_counter_src0; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_src1(struct mali_gp_job *job) ++{ ++ return job->uargs.perf_counter_src1; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value0(struct mali_gp_job *job) ++{ ++ return job->perf_counter_value0; ++} ++ ++MALI_STATIC_INLINE u32 mali_gp_job_get_perf_counter_value1(struct mali_gp_job *job) ++{ ++ return job->perf_counter_value1; ++} ++ ++MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_src0(struct mali_gp_job *job, u32 src) ++{ ++ job->uargs.perf_counter_src0 = src; ++} ++ ++MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_src1(struct mali_gp_job *job, u32 src) ++{ ++ job->uargs.perf_counter_src1 = src; ++} ++ ++MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value0(struct mali_gp_job *job, u32 value) ++{ ++ job->perf_counter_value0 = value; ++} ++ ++MALI_STATIC_INLINE void mali_gp_job_set_perf_counter_value1(struct mali_gp_job *job, u32 value) ++{ ++ job->perf_counter_value1 = value; ++} ++ ++/** ++ * Returns MALI_TRUE if first job is after the second job, ordered by job ID. ++ * ++ * @param first First job. ++ * @param second Second job. ++ * @return MALI_TRUE if first job should be ordered after the second job, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_gp_job_is_after(struct mali_gp_job *first, struct mali_gp_job *second) ++{ ++ /* A span is used to handle job ID wrapping. */ ++ return (mali_gp_job_get_id(first) - mali_gp_job_get_id(second)) < MALI_SCHEDULER_JOB_ID_SPAN; ++} ++ ++/** ++ * Release reference on tracker for PP job that depends on this GP job. ++ * ++ * @note If GP job has a reference on tracker, this function MUST be called before the GP job is ++ * deleted. ++ * ++ * @param job GP job that is done. ++ * @param success MALI_TRUE if job completed successfully, MALI_FALSE if not. ++ * @return A scheduling bitmask indicating whether scheduling needs to be done. ++ */ ++mali_scheduler_mask mali_gp_job_signal_pp_tracker(struct mali_gp_job *job, mali_bool success); ++ ++#endif /* __MALI_GP_JOB_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.c +new file mode 100644 +index 0000000..36a29e3 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.c +@@ -0,0 +1,701 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_gp_scheduler.h" ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_scheduler.h" ++#include "mali_gp.h" ++#include "mali_gp_job.h" ++#include "mali_group.h" ++#include "mali_timeline.h" ++#include "mali_osk_profiling.h" ++#include "mali_kernel_utilization.h" ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++#include ++#include ++#endif ++ ++enum mali_gp_slot_state { ++ MALI_GP_SLOT_STATE_IDLE, ++ MALI_GP_SLOT_STATE_WORKING, ++ MALI_GP_SLOT_STATE_DISABLED, ++}; ++ ++/* A render slot is an entity which jobs can be scheduled onto */ ++struct mali_gp_slot { ++ struct mali_group *group; ++ /* ++ * We keep track of the state here as well as in the group object ++ * so we don't need to take the group lock so often (and also avoid clutter with the working lock) ++ */ ++ enum mali_gp_slot_state state; ++ u32 returned_cookie; ++}; ++ ++static u32 gp_version = 0; ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(job_queue); /* List of unscheduled jobs. */ ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(job_queue_high); /* List of unscheduled high priority jobs. */ ++static struct mali_gp_slot slot; ++ ++/* Variables to allow safe pausing of the scheduler */ ++static _mali_osk_wait_queue_t *gp_scheduler_working_wait_queue = NULL; ++static u32 pause_count = 0; ++ ++static mali_bool mali_gp_scheduler_is_suspended(void *data); ++static void mali_gp_scheduler_job_queued(void); ++static void mali_gp_scheduler_job_completed(void); ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++static _mali_osk_spinlock_irq_t *gp_scheduler_lock = NULL; ++#else ++static _mali_osk_spinlock_t *gp_scheduler_lock = NULL; ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ ++_mali_osk_errcode_t mali_gp_scheduler_initialize(void) ++{ ++ u32 num_groups; ++ u32 i; ++ _mali_osk_errcode_t ret = _MALI_OSK_ERR_OK; ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ gp_scheduler_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER); ++#else ++ gp_scheduler_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ if (NULL == gp_scheduler_lock) { ++ ret = _MALI_OSK_ERR_NOMEM; ++ goto cleanup; ++ } ++ ++ gp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); ++ if (NULL == gp_scheduler_working_wait_queue) { ++ ret = _MALI_OSK_ERR_NOMEM; ++ goto cleanup; ++ } ++ ++ /* Find all the available GP cores */ ++ num_groups = mali_group_get_glob_num_groups(); ++ for (i = 0; i < num_groups; i++) { ++ struct mali_group *group = mali_group_get_glob_group(i); ++ MALI_DEBUG_ASSERT(NULL != group); ++ if (NULL != group) { ++ struct mali_gp_core *gp_core = mali_group_get_gp_core(group); ++ if (NULL != gp_core) { ++ if (0 == gp_version) { ++ /* Retrieve GP version */ ++ gp_version = mali_gp_core_get_version(gp_core); ++ } ++ slot.group = group; ++ slot.state = MALI_GP_SLOT_STATE_IDLE; ++ break; /* There is only one GP, no point in looking for more */ ++ } ++ } else { ++ ret = _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ goto cleanup; ++ } ++ } ++ ++ return _MALI_OSK_ERR_OK; ++ ++cleanup: ++ if (NULL != gp_scheduler_working_wait_queue) { ++ _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue); ++ gp_scheduler_working_wait_queue = NULL; ++ } ++ ++ if (NULL != gp_scheduler_lock) { ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_term(gp_scheduler_lock); ++#else ++ _mali_osk_spinlock_term(gp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ gp_scheduler_lock = NULL; ++ } ++ ++ return ret; ++} ++ ++void mali_gp_scheduler_terminate(void) ++{ ++ MALI_DEBUG_ASSERT( MALI_GP_SLOT_STATE_IDLE == slot.state ++ || MALI_GP_SLOT_STATE_DISABLED == slot.state); ++ MALI_DEBUG_ASSERT_POINTER(slot.group); ++ mali_group_delete(slot.group); ++ ++ _mali_osk_wait_queue_term(gp_scheduler_working_wait_queue); ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_term(gp_scheduler_lock); ++#else ++ _mali_osk_spinlock_term(gp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++} ++ ++MALI_STATIC_INLINE void mali_gp_scheduler_lock(void) ++{ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_lock(gp_scheduler_lock); ++#else ++ _mali_osk_spinlock_lock(gp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ MALI_DEBUG_PRINT(5, ("Mali GP scheduler: GP scheduler lock taken\n")); ++} ++ ++MALI_STATIC_INLINE void mali_gp_scheduler_unlock(void) ++{ ++ MALI_DEBUG_PRINT(5, ("Mali GP scheduler: Releasing GP scheduler lock\n")); ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_unlock(gp_scheduler_lock); ++#else ++ _mali_osk_spinlock_unlock(gp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++} ++ ++#if defined(DEBUG) ++#define MALI_ASSERT_GP_SCHEDULER_LOCKED() MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock) ++#else ++#define MALI_ASSERT_GP_SCHEDULER_LOCKED() do {} while (0) ++#endif /* defined(DEBUG) */ ++ ++/* Group and scheduler must be locked when entering this function. Both will be unlocked before ++ * exiting. */ ++static void mali_gp_scheduler_schedule_internal_and_unlock(void) ++{ ++ struct mali_gp_job *job = NULL; ++ ++ MALI_DEBUG_ASSERT_LOCK_HELD(slot.group->lock); ++ MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); ++ ++ if (0 < pause_count || MALI_GP_SLOT_STATE_IDLE != slot.state || ++ (_mali_osk_list_empty(&job_queue) && _mali_osk_list_empty(&job_queue_high))) { ++ mali_gp_scheduler_unlock(); ++ mali_group_unlock(slot.group); ++ MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Nothing to schedule (paused=%u, idle slots=%u)\n", ++ pause_count, MALI_GP_SLOT_STATE_IDLE == slot.state ? 1 : 0)); ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch(mali_gp_get_hw_core_desc(group->gp_core), sched_clock(), 0, 0, 0); ++#endif ++ return; /* Nothing to do, so early out */ ++ } ++ ++ /* Get next job in queue */ ++ if (!_mali_osk_list_empty(&job_queue_high)) { ++ job = _MALI_OSK_LIST_ENTRY(job_queue_high.next, struct mali_gp_job, list); ++ } else { ++ MALI_DEBUG_ASSERT(!_mali_osk_list_empty(&job_queue)); ++ job = _MALI_OSK_LIST_ENTRY(job_queue.next, struct mali_gp_job, list); ++ } ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ /* Remove the job from queue */ ++ _mali_osk_list_del(&job->list); ++ ++ /* Mark slot as busy */ ++ slot.state = MALI_GP_SLOT_STATE_WORKING; ++ ++ mali_gp_scheduler_unlock(); ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Starting job %u (0x%08X)\n", mali_gp_job_get_id(job), job)); ++ ++ mali_group_start_gp_job(slot.group, job); ++ mali_group_unlock(slot.group); ++} ++ ++void mali_gp_scheduler_schedule(void) ++{ ++ mali_group_lock(slot.group); ++ mali_gp_scheduler_lock(); ++ ++ mali_gp_scheduler_schedule_internal_and_unlock(); ++} ++ ++static void mali_gp_scheduler_return_job_to_user(struct mali_gp_job *job, mali_bool success) ++{ ++ _mali_uk_gp_job_finished_s *jobres = job->finished_notification->result_buffer; ++ _mali_osk_memset(jobres, 0, sizeof(_mali_uk_gp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ ++ jobres->user_job_ptr = mali_gp_job_get_user_id(job); ++ if (MALI_TRUE == success) { ++ jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; ++ } else { ++ jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; ++ } ++ ++ jobres->heap_current_addr = mali_gp_job_get_current_heap_addr(job); ++ jobres->perf_counter0 = mali_gp_job_get_perf_counter_value0(job); ++ jobres->perf_counter1 = mali_gp_job_get_perf_counter_value1(job); ++ ++ mali_session_send_notification(mali_gp_job_get_session(job), job->finished_notification); ++ job->finished_notification = NULL; ++ ++ mali_gp_job_delete(job); ++ mali_gp_scheduler_job_completed(); ++} ++ ++/* Group must be locked when entering this function. Will be unlocked before exiting. */ ++void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++ MALI_DEBUG_ASSERT(slot.group == group); ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) completed (%s)\n", mali_gp_job_get_id(job), job, success ? "success" : "failure")); ++ ++ /* Release tracker. */ ++ schedule_mask |= mali_timeline_tracker_release(&job->tracker); ++ ++ /* Signal PP job. */ ++ schedule_mask |= mali_gp_job_signal_pp_tracker(job, success); ++ ++ mali_gp_scheduler_lock(); ++ ++ /* Mark slot as idle again */ ++ slot.state = MALI_GP_SLOT_STATE_IDLE; ++ ++ /* If paused, then this was the last job, so wake up sleeping workers */ ++ if (pause_count > 0) { ++ _mali_osk_wait_queue_wake_up(gp_scheduler_working_wait_queue); ++ } ++ ++ /* Schedule any queued GP jobs on this group. */ ++ mali_gp_scheduler_schedule_internal_and_unlock(); ++ ++ /* GP is now scheduled, removing it from the mask. */ ++ schedule_mask &= ~MALI_SCHEDULER_MASK_GP; ++ ++ if (MALI_SCHEDULER_MASK_EMPTY != schedule_mask) { ++ /* Releasing the tracker activated other jobs that need scheduling. */ ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE); ++ } ++ ++ /* Sends the job end message to user space and free the job object */ ++ mali_gp_scheduler_return_job_to_user(job, success); ++} ++ ++void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job) ++{ ++ _mali_uk_gp_job_suspended_s * jobres; ++ _mali_osk_notification_t * notification; ++ ++ mali_gp_scheduler_lock(); ++ ++ notification = job->oom_notification; ++ job->oom_notification = NULL; ++ slot.returned_cookie = mali_gp_job_get_id(job); ++ ++ jobres = (_mali_uk_gp_job_suspended_s *)notification->result_buffer; ++ jobres->user_job_ptr = mali_gp_job_get_user_id(job); ++ jobres->cookie = mali_gp_job_get_id(job); ++ ++ mali_gp_scheduler_unlock(); ++ ++ mali_session_send_notification(mali_gp_job_get_session(job), notification); ++ ++ /* ++ * If this function failed, then we could return the job to user space right away, ++ * but there is a job timer anyway that will do that eventually. ++ * This is not exactly a common case anyway. ++ */ ++} ++ ++void mali_gp_scheduler_suspend(void) ++{ ++ mali_gp_scheduler_lock(); ++ pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ ++ mali_gp_scheduler_unlock(); ++ ++ _mali_osk_wait_queue_wait_event(gp_scheduler_working_wait_queue, mali_gp_scheduler_is_suspended, NULL); ++} ++ ++void mali_gp_scheduler_resume(void) ++{ ++ mali_gp_scheduler_lock(); ++ pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ ++ mali_gp_scheduler_unlock(); ++ if (0 == pause_count) { ++ mali_gp_scheduler_schedule(); ++ } ++} ++ ++mali_timeline_point mali_gp_scheduler_submit_job(struct mali_session_data *session, struct mali_gp_job *job) ++{ ++ mali_timeline_point point; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ mali_gp_scheduler_job_queued(); ++ ++ /* Add job to Timeline system. */ ++ point = mali_timeline_system_add_tracker(session->timeline_system, &job->tracker, MALI_TIMELINE_GP); ++ ++ return point; ++} ++ ++_mali_osk_errcode_t _mali_ukk_gp_start_job(void *ctx, _mali_uk_gp_start_job_s *uargs) ++{ ++ struct mali_session_data *session; ++ struct mali_gp_job *job; ++ mali_timeline_point point; ++ u32 __user *timeline_point_ptr = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(uargs); ++ MALI_DEBUG_ASSERT_POINTER(ctx); ++ ++ session = (struct mali_session_data*)ctx; ++ ++ job = mali_gp_job_create(session, uargs, mali_scheduler_get_new_id(), NULL); ++ if (NULL == job) { ++ MALI_PRINT_ERROR(("Failed to create GP job.\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ timeline_point_ptr = (u32 __user *) job->uargs.timeline_point_ptr; ++ ++ point = mali_gp_scheduler_submit_job(session, job); ++ ++ if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) { ++ /* Let user space know that something failed after the job was started. */ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores(_mali_uk_get_gp_number_of_cores_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ args->number_of_cores = 1; ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_gp_core_version(_mali_uk_get_gp_core_version_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ args->version = gp_version; ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_gp_suspend_response(_mali_uk_gp_suspend_response_s *args) ++{ ++ struct mali_session_data *session; ++ struct mali_gp_job *resumed_job; ++ _mali_osk_notification_t *new_notification = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ ++ if (NULL == args->ctx) { ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ session = (struct mali_session_data*)args->ctx; ++ if (NULL == session) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) { ++ new_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_GP_STALLED, sizeof(_mali_uk_gp_job_suspended_s)); ++ ++ if (NULL == new_notification) { ++ MALI_PRINT_ERROR(("Mali GP scheduler: Failed to allocate notification object. Will abort GP job.\n")); ++ mali_group_lock(slot.group); ++ mali_group_abort_gp_job(slot.group, args->cookie); ++ mali_group_unlock(slot.group); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ } ++ ++ mali_group_lock(slot.group); ++ ++ if (_MALIGP_JOB_RESUME_WITH_NEW_HEAP == args->code) { ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Resuming job %u with new heap; 0x%08X - 0x%08X\n", args->cookie, args->arguments[0], args->arguments[1])); ++ ++ resumed_job = mali_group_resume_gp_with_new_heap(slot.group, args->cookie, args->arguments[0], args->arguments[1]); ++ if (NULL != resumed_job) { ++ resumed_job->oom_notification = new_notification; ++ mali_group_unlock(slot.group); ++ return _MALI_OSK_ERR_OK; ++ } else { ++ mali_group_unlock(slot.group); ++ _mali_osk_notification_delete(new_notification); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Mali GP scheduler: Aborting job %u, no new heap provided\n", args->cookie)); ++ mali_group_abort_gp_job(slot.group, args->cookie); ++ mali_group_unlock(slot.group); ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_gp_scheduler_abort_session(struct mali_session_data *session) ++{ ++ struct mali_gp_job *job, *tmp; ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs); ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT(session->is_aborting); ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Aborting all jobs from session 0x%08X.\n", session)); ++ ++ mali_gp_scheduler_lock(); ++ ++ /* Find all jobs from the aborting session. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue, struct mali_gp_job, list) { ++ if (job->session == session) { ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Removing job %u (0x%08X) from queue.\n", mali_gp_job_get_id(job), job)); ++ _mali_osk_list_move(&job->list, &removed_jobs); ++ } ++ } ++ ++ /* Find all high priority jobs from the aborting session. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &job_queue_high, struct mali_gp_job, list) { ++ if (job->session == session) { ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Removing job %u (0x%08X) from queue.\n", mali_gp_job_get_id(job), job)); ++ _mali_osk_list_move(&job->list, &removed_jobs); ++ } ++ } ++ ++ mali_gp_scheduler_unlock(); ++ ++ /* Release and delete all found jobs from the aborting session. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &removed_jobs, struct mali_gp_job, list) { ++ mali_timeline_tracker_release(&job->tracker); ++ mali_gp_job_signal_pp_tracker(job, MALI_FALSE); ++ mali_gp_job_delete(job); ++ mali_gp_scheduler_job_completed(); ++ } ++ ++ /* Abort any running jobs from the session. */ ++ mali_group_abort_session(slot.group, session); ++} ++ ++static mali_bool mali_gp_scheduler_is_suspended(void *data) ++{ ++ mali_bool ret; ++ ++ /* This callback does not use the data pointer. */ ++ MALI_IGNORE(data); ++ ++ mali_gp_scheduler_lock(); ++ ret = pause_count > 0 && (slot.state == MALI_GP_SLOT_STATE_IDLE || slot.state == MALI_GP_SLOT_STATE_DISABLED); ++ mali_gp_scheduler_unlock(); ++ ++ return ret; ++} ++ ++ ++#if MALI_STATE_TRACKING ++u32 mali_gp_scheduler_dump_state(char *buf, u32 size) ++{ ++ int n = 0; ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "GP\n"); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue) ? "empty" : "not empty"); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tHigh priority queue is %s\n", _mali_osk_list_empty(&job_queue_high) ? "empty" : "not empty"); ++ ++ n += mali_group_dump_state(slot.group, buf + n, size - n); ++ n += _mali_osk_snprintf(buf + n, size - n, "\n"); ++ ++ return n; ++} ++#endif ++ ++void mali_gp_scheduler_reset_all_groups(void) ++{ ++ if (NULL != slot.group) { ++ mali_group_lock(slot.group); ++ mali_group_reset(slot.group); ++ mali_group_unlock(slot.group); ++ } ++} ++ ++void mali_gp_scheduler_zap_all_active(struct mali_session_data *session) ++{ ++ if (NULL != slot.group) { ++ mali_group_zap_session(slot.group, session); ++ } ++} ++ ++void mali_gp_scheduler_enable_group(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT(slot.group == group); ++ MALI_DEBUG_PRINT(2, ("Mali GP scheduler: enabling gp group %p\n", group)); ++ ++ mali_group_lock(group); ++ ++ if (MALI_GROUP_STATE_DISABLED != group->state) { ++ mali_group_unlock(group); ++ MALI_DEBUG_PRINT(2, ("Mali GP scheduler: gp group %p already enabled\n", group)); ++ return; ++ } ++ ++ mali_gp_scheduler_lock(); ++ ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state); ++ MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_DISABLED == slot.state); ++ slot.state = MALI_GP_SLOT_STATE_IDLE; ++ group->state = MALI_GROUP_STATE_IDLE; ++ ++ mali_group_power_on_group(group); ++ mali_group_reset(group); ++ ++ /* Pick up any jobs that might have been queued while the GP group was disabled. */ ++ mali_gp_scheduler_schedule_internal_and_unlock(); ++} ++ ++void mali_gp_scheduler_disable_group(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT(slot.group == group); ++ MALI_DEBUG_PRINT(2, ("Mali GP scheduler: disabling gp group %p\n", group)); ++ ++ mali_gp_scheduler_suspend(); ++ mali_group_lock(group); ++ mali_gp_scheduler_lock(); ++ ++ MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state ++ || MALI_GROUP_STATE_DISABLED == group->state); ++ ++ if (MALI_GROUP_STATE_DISABLED == group->state) { ++ MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_DISABLED == slot.state); ++ MALI_DEBUG_PRINT(2, ("Mali GP scheduler: gp group %p already disabled\n", group)); ++ } else { ++ MALI_DEBUG_ASSERT(MALI_GP_SLOT_STATE_IDLE == slot.state); ++ slot.state = MALI_GP_SLOT_STATE_DISABLED; ++ group->state = MALI_GROUP_STATE_DISABLED; ++ ++ mali_group_power_off_group(group, MALI_TRUE); ++ } ++ ++ mali_gp_scheduler_unlock(); ++ mali_group_unlock(group); ++ mali_gp_scheduler_resume(); ++} ++ ++static mali_scheduler_mask mali_gp_scheduler_queue_job(struct mali_gp_job *job) ++{ ++ _mali_osk_list_t *queue = NULL; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ struct mali_gp_job *iter, *tmp; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->session); ++ ++ MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_GP_ENQUEUE, job->pid, job->tid, job->uargs.frame_builder_id, job->uargs.flush_id, 0); ++ ++ job->cache_order = mali_scheduler_get_new_cache_order(); ++ ++ /* Determine which queue the job should be added to. */ ++ if (job->session->use_high_priority_job_queue) { ++ queue = &job_queue_high; ++ } else { ++ queue = &job_queue; ++ } ++ ++ /* Find position in queue where job should be added. */ ++ _MALI_OSK_LIST_FOREACHENTRY_REVERSE(iter, tmp, queue, struct mali_gp_job, list) { ++ if (mali_gp_job_is_after(job, iter)) { ++ break; ++ } ++ } ++ ++ /* Add job to queue. */ ++ _mali_osk_list_add(&job->list, &iter->list); ++ ++ /* Set schedule bitmask if the GP core is idle. */ ++ if (MALI_GP_SLOT_STATE_IDLE == slot.state) { ++ schedule_mask |= MALI_SCHEDULER_MASK_GP; ++ } ++ ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_job_enqueue(mali_gp_job_get_tid(job), mali_gp_job_get_id(job), "GP"); ++#endif ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) queued\n", mali_gp_job_get_id(job), job)); ++ ++ return schedule_mask; ++} ++ ++mali_scheduler_mask mali_gp_scheduler_activate_job(struct mali_gp_job *job) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->session); ++ ++ MALI_DEBUG_PRINT(4, ("Mali GP scheduler: Timeline activation for job %u (0x%08X).\n", mali_gp_job_get_id(job), job)); ++ ++ mali_gp_scheduler_lock(); ++ ++ if (unlikely(job->session->is_aborting)) { ++ /* Before checking if the session is aborting, the scheduler must be locked. */ ++ MALI_DEBUG_ASSERT_LOCK_HELD(gp_scheduler_lock); ++ ++ MALI_DEBUG_PRINT(3, ("Mali GP scheduler: Job %u (0x%08X) activated while session is aborting.\n", mali_gp_job_get_id(job), job)); ++ ++ /* This job should not be on any list. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); ++ ++ mali_gp_scheduler_unlock(); ++ ++ /* Release tracker and delete job. */ ++ mali_timeline_tracker_release(&job->tracker); ++ mali_gp_job_signal_pp_tracker(job, MALI_FALSE); ++ mali_gp_job_delete(job); ++ mali_gp_scheduler_job_completed(); ++ ++ /* Since we are aborting we ignore the scheduler mask. */ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++ ++ /* GP job is ready to run, queue it. */ ++ schedule_mask = mali_gp_scheduler_queue_job(job); ++ ++ mali_gp_scheduler_unlock(); ++ ++ return schedule_mask; ++} ++ ++static void mali_gp_scheduler_job_queued(void) ++{ ++ /* We hold a PM reference for every job we hold queued (and running) */ ++ _mali_osk_pm_dev_ref_add(); ++ ++ if (mali_utilization_enabled()) { ++ /* ++ * We cheat a little bit by counting the PP as busy from the time a GP job is queued. ++ * This will be fine because we only loose the tiny idle gap between jobs, but ++ * we will instead get less utilization work to do (less locks taken) ++ */ ++ mali_utilization_gp_start(); ++ } ++} ++ ++static void mali_gp_scheduler_job_completed(void) ++{ ++ /* Release the PM reference we got in the mali_gp_scheduler_job_queued() function */ ++ _mali_osk_pm_dev_ref_dec(); ++ ++ if (mali_utilization_enabled()) { ++ mali_utilization_gp_end(); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.h +new file mode 100644 +index 0000000..8be9c47 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_gp_scheduler.h +@@ -0,0 +1,101 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_GP_SCHEDULER_H__ ++#define __MALI_GP_SCHEDULER_H__ ++ ++#include "mali_osk.h" ++#include "mali_gp_job.h" ++#include "mali_group.h" ++ ++_mali_osk_errcode_t mali_gp_scheduler_initialize(void); ++void mali_gp_scheduler_terminate(void); ++ ++void mali_gp_scheduler_job_done(struct mali_group *group, struct mali_gp_job *job, mali_bool success); ++void mali_gp_scheduler_oom(struct mali_group *group, struct mali_gp_job *job); ++u32 mali_gp_scheduler_dump_state(char *buf, u32 size); ++ ++void mali_gp_scheduler_suspend(void); ++void mali_gp_scheduler_resume(void); ++ ++/** ++ * @brief Abort all running and queued GP jobs from session. ++ * ++* This functions aborts all GP jobs from the specified session. Queued jobs are removed from the ++* queue and jobs currently running on a core will be aborted. ++ * ++ * @param session Session that is aborting. ++ */ ++void mali_gp_scheduler_abort_session(struct mali_session_data *session); ++ ++/** ++ * @brief Reset all groups ++ * ++ * This function resets all groups known by the GP scheuduler. This must be ++ * called after the Mali HW has been powered on in order to reset the HW. ++ */ ++void mali_gp_scheduler_reset_all_groups(void); ++ ++/** ++ * @brief Zap TLB on all groups with \a session active ++ * ++ * The scheculer will zap the session on all groups it owns. ++ */ ++void mali_gp_scheduler_zap_all_active(struct mali_session_data *session); ++ ++/** ++ * @brief Re-enable a group that has been disabled with mali_gp_scheduler_disable_group ++ * ++ * If a Mali PMU is present, the group will be powered back on and added back ++ * into the GP scheduler. ++ * ++ * @param group Pointer to the group to enable ++ */ ++void mali_gp_scheduler_enable_group(struct mali_group *group); ++ ++/** ++ * @brief Disable a group ++ * ++ * The group will be taken out of the GP scheduler and powered off, if a Mali ++ * PMU is present. ++ * ++ * @param group Pointer to the group to disable ++ */ ++void mali_gp_scheduler_disable_group(struct mali_group *group); ++ ++/** ++ * @brief Used by the Timeline system to queue a GP job. ++ * ++ * @note @ref mali_scheduler_schedule_from_mask() should be called if this function returns non-zero. ++ * ++ * @param job The GP job that is being activated. ++ * ++ * @return A scheduling bitmask that can be used to decide if scheduling is necessary after this ++ * call. ++ */ ++mali_scheduler_mask mali_gp_scheduler_activate_job(struct mali_gp_job *job); ++ ++/** ++ * @brief Schedule queued jobs on idle cores. ++ */ ++void mali_gp_scheduler_schedule(void); ++ ++/** ++ * @brief Submit a GP job to the GP scheduler. ++ * ++ * This will add the GP job to the Timeline system. ++ * ++ * @param session Session this job belongs to. ++ * @param job GP job that will be submitted ++ * @return Point on GP timeline for job. ++ */ ++mali_timeline_point mali_gp_scheduler_submit_job(struct mali_session_data *session, struct mali_gp_job *job); ++ ++#endif /* __MALI_GP_SCHEDULER_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.c +new file mode 100644 +index 0000000..7383dea +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.c +@@ -0,0 +1,1855 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_group.h" ++#include "mali_osk.h" ++#include "mali_l2_cache.h" ++#include "mali_gp.h" ++#include "mali_pp.h" ++#include "mali_mmu.h" ++#include "mali_dlbu.h" ++#include "mali_broadcast.h" ++#include "mali_scheduler.h" ++#include "mali_osk_profiling.h" ++#include "mali_pm_domain.h" ++#include "mali_pm.h" ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++#include ++#include ++#endif ++ ++ ++static void mali_group_bottom_half_mmu(void *data); ++static void mali_group_bottom_half_gp(void *data); ++static void mali_group_bottom_half_pp(void *data); ++ ++static void mali_group_timeout(void *data); ++static void mali_group_reset_pp(struct mali_group *group); ++static void mali_group_reset_mmu(struct mali_group *group); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++static void mali_group_report_l2_cache_counters_per_core(struct mali_group *group, u32 core_num); ++#endif /* #if defined(CONFIG_MALI400_PROFILING) */ ++ ++/* ++ * The group object is the most important object in the device driver, ++ * and acts as the center of many HW operations. ++ * The reason for this is that operations on the MMU will affect all ++ * cores connected to this MMU (a group is defined by the MMU and the ++ * cores which are connected to this). ++ * The group lock is thus the most important lock, followed by the ++ * GP and PP scheduler locks. They must be taken in the following ++ * order: ++ * GP/PP lock first, then group lock(s). ++ */ ++ ++static struct mali_group *mali_global_groups[MALI_MAX_NUMBER_OF_GROUPS] = { NULL, }; ++static u32 mali_global_num_groups = 0; ++ ++/* timer related */ ++int mali_max_job_runtime = MALI_MAX_JOB_RUNTIME_DEFAULT; ++ ++/* local helper functions */ ++static void mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session); ++static void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session); ++static void mali_group_recovery_reset(struct mali_group *group); ++static void mali_group_mmu_page_fault_and_unlock(struct mali_group *group); ++ ++static void mali_group_post_process_job_pp(struct mali_group *group); ++static void mali_group_post_process_job_gp(struct mali_group *group, mali_bool suspend); ++ ++void mali_group_lock(struct mali_group *group) ++{ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_lock(group->lock); ++#else ++ _mali_osk_spinlock_lock(group->lock); ++#endif ++ MALI_DEBUG_PRINT(5, ("Mali group: Group lock taken 0x%08X\n", group)); ++} ++ ++void mali_group_unlock(struct mali_group *group) ++{ ++ MALI_DEBUG_PRINT(5, ("Mali group: Releasing group lock 0x%08X\n", group)); ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_unlock(group->lock); ++#else ++ _mali_osk_spinlock_unlock(group->lock); ++#endif ++} ++ ++#ifdef DEBUG ++void mali_group_assert_locked(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++} ++#endif ++ ++ ++struct mali_group *mali_group_create(struct mali_l2_cache_core *core, struct mali_dlbu_core *dlbu, struct mali_bcast_unit *bcast) ++{ ++ struct mali_group *group = NULL; ++ ++ if (mali_global_num_groups >= MALI_MAX_NUMBER_OF_GROUPS) { ++ MALI_PRINT_ERROR(("Mali group: Too many group objects created\n")); ++ return NULL; ++ } ++ ++ group = _mali_osk_calloc(1, sizeof(struct mali_group)); ++ if (NULL != group) { ++ group->timeout_timer = _mali_osk_timer_init(); ++ ++ if (NULL != group->timeout_timer) { ++ _mali_osk_lock_order_t order; ++ _mali_osk_timer_setcallback(group->timeout_timer, mali_group_timeout, (void *)group); ++ ++ if (NULL != dlbu) { ++ order = _MALI_OSK_LOCK_ORDER_GROUP_VIRTUAL; ++ } else { ++ order = _MALI_OSK_LOCK_ORDER_GROUP; ++ } ++ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ group->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, order); ++#else ++ group->lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, order); ++#endif ++ ++ if (NULL != group->lock) { ++ group->l2_cache_core[0] = core; ++ group->session = NULL; ++ group->power_is_on = MALI_TRUE; ++ group->state = MALI_GROUP_STATE_IDLE; ++ _mali_osk_list_init(&group->group_list); ++ _mali_osk_list_init(&group->pp_scheduler_list); ++ group->parent_group = NULL; ++ group->l2_cache_core_ref_count[0] = 0; ++ group->l2_cache_core_ref_count[1] = 0; ++ group->bcast_core = bcast; ++ group->dlbu_core = dlbu; ++ ++ mali_global_groups[mali_global_num_groups] = group; ++ mali_global_num_groups++; ++ ++ return group; ++ } ++ _mali_osk_timer_term(group->timeout_timer); ++ } ++ _mali_osk_free(group); ++ } ++ ++ return NULL; ++} ++ ++_mali_osk_errcode_t mali_group_add_mmu_core(struct mali_group *group, struct mali_mmu_core* mmu_core) ++{ ++ /* This group object now owns the MMU core object */ ++ group->mmu= mmu_core; ++ group->bottom_half_work_mmu = _mali_osk_wq_create_work(mali_group_bottom_half_mmu, group); ++ if (NULL == group->bottom_half_work_mmu) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_group_remove_mmu_core(struct mali_group *group) ++{ ++ /* This group object no longer owns the MMU core object */ ++ group->mmu = NULL; ++ if (NULL != group->bottom_half_work_mmu) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_mmu); ++ } ++} ++ ++_mali_osk_errcode_t mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core) ++{ ++ /* This group object now owns the GP core object */ ++ group->gp_core = gp_core; ++ group->bottom_half_work_gp = _mali_osk_wq_create_work(mali_group_bottom_half_gp, group); ++ if (NULL == group->bottom_half_work_gp) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_group_remove_gp_core(struct mali_group *group) ++{ ++ /* This group object no longer owns the GP core object */ ++ group->gp_core = NULL; ++ if (NULL != group->bottom_half_work_gp) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_gp); ++ } ++} ++ ++_mali_osk_errcode_t mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core) ++{ ++ /* This group object now owns the PP core object */ ++ group->pp_core = pp_core; ++ group->bottom_half_work_pp = _mali_osk_wq_create_work(mali_group_bottom_half_pp, group); ++ if (NULL == group->bottom_half_work_pp) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_group_remove_pp_core(struct mali_group *group) ++{ ++ /* This group object no longer owns the PP core object */ ++ group->pp_core = NULL; ++ if (NULL != group->bottom_half_work_pp) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_pp); ++ } ++} ++ ++void mali_group_set_pm_domain(struct mali_group *group, struct mali_pm_domain *domain) ++{ ++ group->pm_domain = domain; ++} ++ ++void mali_group_delete(struct mali_group *group) ++{ ++ u32 i; ++ ++ MALI_DEBUG_PRINT(4, ("Deleting group %p\n", group)); ++ ++ MALI_DEBUG_ASSERT(NULL == group->parent_group); ++ ++ /* Delete the resources that this group owns */ ++ if (NULL != group->gp_core) { ++ mali_gp_delete(group->gp_core); ++ } ++ ++ if (NULL != group->pp_core) { ++ mali_pp_delete(group->pp_core); ++ } ++ ++ if (NULL != group->mmu) { ++ mali_mmu_delete(group->mmu); ++ } ++ ++ if (mali_group_is_virtual(group)) { ++ /* Remove all groups from virtual group */ ++ struct mali_group *child; ++ struct mali_group *temp; ++ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ child->parent_group = NULL; ++ mali_group_delete(child); ++ } ++ ++ mali_dlbu_delete(group->dlbu_core); ++ ++ if (NULL != group->bcast_core) { ++ mali_bcast_unit_delete(group->bcast_core); ++ } ++ } ++ ++ for (i = 0; i < mali_global_num_groups; i++) { ++ if (mali_global_groups[i] == group) { ++ mali_global_groups[i] = NULL; ++ mali_global_num_groups--; ++ ++ if (i != mali_global_num_groups) { ++ /* We removed a group from the middle of the array -- move the last ++ * group to the current position to close the gap */ ++ mali_global_groups[i] = mali_global_groups[mali_global_num_groups]; ++ mali_global_groups[mali_global_num_groups] = NULL; ++ } ++ ++ break; ++ } ++ } ++ ++ if (NULL != group->timeout_timer) { ++ _mali_osk_timer_del(group->timeout_timer); ++ _mali_osk_timer_term(group->timeout_timer); ++ } ++ ++ if (NULL != group->bottom_half_work_mmu) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_mmu); ++ } ++ ++ if (NULL != group->bottom_half_work_gp) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_gp); ++ } ++ ++ if (NULL != group->bottom_half_work_pp) { ++ _mali_osk_wq_delete_work(group->bottom_half_work_pp); ++ } ++ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_term(group->lock); ++#else ++ _mali_osk_spinlock_term(group->lock); ++#endif ++ _mali_osk_free(group); ++} ++ ++MALI_DEBUG_CODE(static void mali_group_print_virtual(struct mali_group *vgroup) ++{ ++ u32 i; ++ struct mali_group *group; ++ struct mali_group *temp; ++ ++ MALI_DEBUG_PRINT(4, ("Virtual group %p\n", vgroup)); ++ MALI_DEBUG_PRINT(4, ("l2_cache_core[0] = %p, ref = %d\n", vgroup->l2_cache_core[0], vgroup->l2_cache_core_ref_count[0])); ++ MALI_DEBUG_PRINT(4, ("l2_cache_core[1] = %p, ref = %d\n", vgroup->l2_cache_core[1], vgroup->l2_cache_core_ref_count[1])); ++ ++ i = 0; ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &vgroup->group_list, struct mali_group, group_list) { ++ MALI_DEBUG_PRINT(4, ("[%d] %p, l2_cache_core[0] = %p\n", i, group, group->l2_cache_core[0])); ++ i++; ++ } ++}) ++ ++/** ++ * @brief Add child group to virtual group parent ++ * ++ * Before calling this function, child must have it's state set to JOINING_VIRTUAL ++ * to ensure it's not touched during the transition period. When this function returns, ++ * child's state will be IN_VIRTUAL. ++ */ ++void mali_group_add_group(struct mali_group *parent, struct mali_group *child, mali_bool update_hw) ++{ ++ mali_bool found; ++ u32 i; ++ struct mali_session_data *child_session; ++ ++ MALI_DEBUG_PRINT(3, ("Adding group %p to virtual group %p\n", child, parent)); ++ ++ MALI_ASSERT_GROUP_LOCKED(parent); ++ ++ MALI_DEBUG_ASSERT(mali_group_is_virtual(parent)); ++ MALI_DEBUG_ASSERT(!mali_group_is_virtual(child)); ++ MALI_DEBUG_ASSERT(NULL == child->parent_group); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_JOINING_VIRTUAL == child->state); ++ ++ _mali_osk_list_addtail(&child->group_list, &parent->group_list); ++ ++ child->state = MALI_GROUP_STATE_IN_VIRTUAL; ++ child->parent_group = parent; ++ ++ MALI_DEBUG_ASSERT_POINTER(child->l2_cache_core[0]); ++ ++ MALI_DEBUG_PRINT(4, ("parent->l2_cache_core: [0] = %p, [1] = %p\n", parent->l2_cache_core[0], parent->l2_cache_core[1])); ++ MALI_DEBUG_PRINT(4, ("child->l2_cache_core: [0] = %p, [1] = %p\n", child->l2_cache_core[0], child->l2_cache_core[1])); ++ ++ /* Keep track of the L2 cache cores of child groups */ ++ found = MALI_FALSE; ++ for (i = 0; i < 2; i++) { ++ if (parent->l2_cache_core[i] == child->l2_cache_core[0]) { ++ MALI_DEBUG_ASSERT(parent->l2_cache_core_ref_count[i] > 0); ++ parent->l2_cache_core_ref_count[i]++; ++ found = MALI_TRUE; ++ } ++ } ++ ++ if (!found) { ++ /* First time we see this L2 cache, add it to our list */ ++ i = (NULL == parent->l2_cache_core[0]) ? 0 : 1; ++ ++ MALI_DEBUG_PRINT(4, ("First time we see l2_cache %p. Adding to [%d] = %p\n", child->l2_cache_core[0], i, parent->l2_cache_core[i])); ++ ++ MALI_DEBUG_ASSERT(NULL == parent->l2_cache_core[i]); ++ ++ parent->l2_cache_core[i] = child->l2_cache_core[0]; ++ parent->l2_cache_core_ref_count[i]++; ++ } ++ ++ /* Update Broadcast Unit and DLBU */ ++ mali_bcast_add_group(parent->bcast_core, child); ++ mali_dlbu_add_group(parent->dlbu_core, child); ++ ++ child_session = child->session; ++ child->session = NULL; ++ ++ /* Above this comment, only software state is updated and the HW is not ++ * touched. Now, check if Mali is powered and skip the rest if it isn't ++ * powered. ++ */ ++ ++ if (!update_hw) { ++ MALI_DEBUG_CODE(mali_group_print_virtual(parent)); ++ return; ++ } ++ ++ /* Update MMU */ ++ if (parent->session == child_session) { ++ mali_mmu_zap_tlb(child->mmu); ++ } else { ++ if (NULL == parent->session) { ++ mali_mmu_activate_empty_page_directory(child->mmu); ++ } else { ++ mali_mmu_activate_page_directory(child->mmu, mali_session_get_page_directory(parent->session)); ++ } ++ } ++ ++ /* Update HW only if power is on */ ++ mali_bcast_reset(parent->bcast_core); ++ mali_dlbu_update_mask(parent->dlbu_core); ++ ++ /* Start job on child when parent is active */ ++ if (NULL != parent->pp_running_job) { ++ struct mali_pp_job *job = parent->pp_running_job; ++ MALI_DEBUG_PRINT(3, ("Group %x joining running job %d on virtual group %x\n", ++ child, mali_pp_job_get_id(job), parent)); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_WORKING == parent->state); ++ mali_pp_job_start(child->pp_core, job, mali_pp_core_get_id(child->pp_core), MALI_TRUE); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(child->pp_core))| ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, ++ mali_pp_job_get_frame_builder_id(job), mali_pp_job_get_flush_id(job), 0, 0, 0); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(child->pp_core))| ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL, ++ mali_pp_job_get_pid(job), mali_pp_job_get_tid(job), 0, 0, 0); ++ } ++ ++ MALI_DEBUG_CODE(mali_group_print_virtual(parent);) ++} ++ ++/** ++ * @brief Remove child group from virtual group parent ++ * ++ * After the child is removed, it's state will be LEAVING_VIRTUAL and must be set ++ * to IDLE before it can be used. ++ */ ++void mali_group_remove_group(struct mali_group *parent, struct mali_group *child) ++{ ++ u32 i; ++ ++ MALI_ASSERT_GROUP_LOCKED(parent); ++ ++ MALI_DEBUG_PRINT(3, ("Removing group %p from virtual group %p\n", child, parent)); ++ ++ MALI_DEBUG_ASSERT(mali_group_is_virtual(parent)); ++ MALI_DEBUG_ASSERT(!mali_group_is_virtual(child)); ++ MALI_DEBUG_ASSERT(parent == child->parent_group); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_IN_VIRTUAL == child->state); ++ /* Removing groups while running is not yet supported. */ ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_IDLE == parent->state); ++ ++ mali_group_lock(child); ++ ++ /* Update Broadcast Unit and DLBU */ ++ mali_bcast_remove_group(parent->bcast_core, child); ++ mali_dlbu_remove_group(parent->dlbu_core, child); ++ ++ /* Update HW only if power is on */ ++ if (mali_pm_is_power_on()) { ++ mali_bcast_reset(parent->bcast_core); ++ mali_dlbu_update_mask(parent->dlbu_core); ++ } ++ ++ _mali_osk_list_delinit(&child->group_list); ++ ++ child->session = parent->session; ++ child->parent_group = NULL; ++ child->state = MALI_GROUP_STATE_LEAVING_VIRTUAL; ++ ++ /* Keep track of the L2 cache cores of child groups */ ++ i = (child->l2_cache_core[0] == parent->l2_cache_core[0]) ? 0 : 1; ++ ++ MALI_DEBUG_ASSERT(child->l2_cache_core[0] == parent->l2_cache_core[i]); ++ ++ parent->l2_cache_core_ref_count[i]--; ++ ++ if (parent->l2_cache_core_ref_count[i] == 0) { ++ parent->l2_cache_core[i] = NULL; ++ } ++ ++ MALI_DEBUG_CODE(mali_group_print_virtual(parent)); ++ ++ mali_group_unlock(child); ++} ++ ++struct mali_group *mali_group_acquire_group(struct mali_group *parent) ++{ ++ struct mali_group *child; ++ ++ MALI_ASSERT_GROUP_LOCKED(parent); ++ ++ MALI_DEBUG_ASSERT(mali_group_is_virtual(parent)); ++ MALI_DEBUG_ASSERT(!_mali_osk_list_empty(&parent->group_list)); ++ ++ child = _MALI_OSK_LIST_ENTRY(parent->group_list.prev, struct mali_group, group_list); ++ ++ mali_group_remove_group(parent, child); ++ ++ return child; ++} ++ ++void mali_group_reset(struct mali_group *group) ++{ ++ /* ++ * This function should not be used to abort jobs, ++ * currently only called during insmod and PM resume ++ */ ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++ MALI_DEBUG_ASSERT(NULL == group->gp_running_job); ++ MALI_DEBUG_ASSERT(NULL == group->pp_running_job); ++ ++ group->session = NULL; ++ ++ if (NULL != group->dlbu_core) { ++ mali_dlbu_reset(group->dlbu_core); ++ } ++ ++ if (NULL != group->bcast_core) { ++ mali_bcast_reset(group->bcast_core); ++ } ++ ++ if (NULL != group->mmu) { ++ mali_group_reset_mmu(group); ++ } ++ ++ if (NULL != group->gp_core) { ++ mali_gp_reset(group->gp_core); ++ } ++ ++ if (NULL != group->pp_core) { ++ mali_group_reset_pp(group); ++ } ++} ++ ++struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group) ++{ ++ return group->gp_core; ++} ++ ++struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group) ++{ ++ return group->pp_core; ++} ++ ++void mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job) ++{ ++ struct mali_session_data *session; ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_IDLE == group->state); ++ ++ session = mali_gp_job_get_session(job); ++ ++ if (NULL != group->l2_cache_core[0]) { ++ mali_l2_cache_invalidate_conditional(group->l2_cache_core[0], mali_gp_job_get_cache_order(job)); ++ } ++ ++ mali_group_activate_page_directory(group, session); ++ ++ mali_gp_job_start(group->gp_core, job); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0) | ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, ++ mali_gp_job_get_frame_builder_id(job), mali_gp_job_get_flush_id(job), 0, 0, 0); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START | ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), ++ mali_gp_job_get_pid(job), mali_gp_job_get_tid(job), 0, 0, 0); ++#if defined(CONFIG_MALI400_PROFILING) ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) ++ mali_group_report_l2_cache_counters_per_core(group, 0); ++#endif /* #if defined(CONFIG_MALI400_PROFILING) */ ++ ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch(mali_gp_get_hw_core_desc(group->gp_core), sched_clock(), ++ mali_gp_job_get_pid(job), 0, mali_gp_job_get_id(job)); ++#endif ++ ++ group->gp_running_job = job; ++ group->state = MALI_GROUP_STATE_WORKING; ++ ++ /* Setup the timeout timer value and save the job id for the job running on the gp core */ ++ _mali_osk_timer_mod(group->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); ++} ++ ++void mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job) ++{ ++ struct mali_session_data *session; ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_IDLE == group->state); ++ ++ session = mali_pp_job_get_session(job); ++ ++ if (NULL != group->l2_cache_core[0]) { ++ mali_l2_cache_invalidate_conditional(group->l2_cache_core[0], mali_pp_job_get_cache_order(job)); ++ } ++ ++ if (NULL != group->l2_cache_core[1]) { ++ mali_l2_cache_invalidate_conditional(group->l2_cache_core[1], mali_pp_job_get_cache_order(job)); ++ } ++ ++ mali_group_activate_page_directory(group, session); ++ ++ if (mali_group_is_virtual(group)) { ++ struct mali_group *child; ++ struct mali_group *temp; ++ u32 core_num = 0; ++ ++ MALI_DEBUG_ASSERT( mali_pp_job_is_virtual(job)); ++ ++ /* Configure DLBU for the job */ ++ mali_dlbu_config_job(group->dlbu_core, job); ++ ++ /* Write stack address for each child group */ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ mali_pp_write_addr_stack(child->pp_core, job); ++ core_num++; ++ } ++ ++ /* Try to use DMA unit to start job, fallback to writing directly to the core */ ++ MALI_DEBUG_ASSERT(mali_dma_cmd_buf_is_valid(&job->dma_cmd_buf)); ++ if (_MALI_OSK_ERR_OK != mali_dma_start(mali_dma_get_global_dma_core(), &job->dma_cmd_buf)) { ++ mali_pp_job_start(group->pp_core, job, sub_job, MALI_FALSE); ++ } ++ } else { ++ mali_pp_job_start(group->pp_core, job, sub_job, MALI_FALSE); ++ } ++ ++ /* if the group is virtual, loop through physical groups which belong to this group ++ * and call profiling events for its cores as virtual */ ++ if (MALI_TRUE == mali_group_is_virtual(group)) { ++ struct mali_group *child; ++ struct mali_group *temp; ++ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(child->pp_core))| ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, ++ mali_pp_job_get_frame_builder_id(job), mali_pp_job_get_flush_id(job), 0, 0, 0); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(child->pp_core))| ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL, ++ mali_pp_job_get_pid(job), mali_pp_job_get_tid(job), 0, 0, 0); ++ } ++#if defined(CONFIG_MALI400_PROFILING) ++ if (0 != group->l2_cache_core_ref_count[0]) { ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[0])); ++ } ++ } ++ if (0 != group->l2_cache_core_ref_count[1]) { ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[1])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[1]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[1])); ++ } ++ } ++#endif /* #if defined(CONFIG_MALI400_PROFILING) */ ++ } else { /* group is physical - call profiling events for physical cores */ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(group->pp_core))| ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH, ++ mali_pp_job_get_frame_builder_id(job), mali_pp_job_get_flush_id(job), 0, 0, 0); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(group->pp_core))| ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_PHYSICAL, ++ mali_pp_job_get_pid(job), mali_pp_job_get_tid(job), 0, 0, 0); ++#if defined(CONFIG_MALI400_PROFILING) ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[0])); ++ } ++#endif /* #if defined(CONFIG_MALI400_PROFILING) */ ++ } ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), mali_pp_job_get_tid(job), 0, mali_pp_job_get_id(job)); ++#endif ++ group->pp_running_job = job; ++ group->pp_running_sub_job = sub_job; ++ group->state = MALI_GROUP_STATE_WORKING; ++ ++ /* Setup the timeout timer value and save the job id for the job running on the pp core */ ++ _mali_osk_timer_mod(group->timeout_timer, _mali_osk_time_mstoticks(mali_max_job_runtime)); ++} ++ ++struct mali_gp_job *mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ if (group->state != MALI_GROUP_STATE_OOM || ++ mali_gp_job_get_id(group->gp_running_job) != job_id) { ++ return NULL; /* Illegal request or job has already been aborted */ ++ } ++ ++ if (NULL != group->l2_cache_core[0]) { ++ mali_l2_cache_invalidate(group->l2_cache_core[0]); ++ } ++ ++ mali_mmu_zap_tlb_without_stall(group->mmu); ++ ++ mali_gp_resume_with_new_heap(group->gp_core, start_addr, end_addr); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), 0, 0, 0, 0, 0); ++ ++ group->state = MALI_GROUP_STATE_WORKING; ++ ++ return group->gp_running_job; ++} ++ ++static void mali_group_reset_mmu(struct mali_group *group) ++{ ++ struct mali_group *child; ++ struct mali_group *temp; ++ _mali_osk_errcode_t err; ++ ++ if (!mali_group_is_virtual(group)) { ++ /* This is a physical group or an idle virtual group -- simply wait for ++ * the reset to complete. */ ++ err = mali_mmu_reset(group->mmu); ++ MALI_DEBUG_ASSERT(_MALI_OSK_ERR_OK == err); ++ } else { /* virtual group */ ++ err = mali_mmu_reset(group->mmu); ++ if (_MALI_OSK_ERR_OK == err) { ++ return; ++ } ++ ++ /* Loop through all members of this virtual group and wait ++ * until they are done resetting. ++ */ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ err = mali_mmu_reset(child->mmu); ++ MALI_DEBUG_ASSERT(_MALI_OSK_ERR_OK == err); ++ } ++ } ++} ++ ++static void mali_group_reset_pp(struct mali_group *group) ++{ ++ struct mali_group *child; ++ struct mali_group *temp; ++ ++ mali_pp_reset_async(group->pp_core); ++ ++ if (!mali_group_is_virtual(group) || NULL == group->pp_running_job) { ++ /* This is a physical group or an idle virtual group -- simply wait for ++ * the reset to complete. */ ++ mali_pp_reset_wait(group->pp_core); ++ } else { /* virtual group */ ++ /* Loop through all members of this virtual group and wait until they ++ * are done resetting. ++ */ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ mali_pp_reset_wait(child->pp_core); ++ } ++ } ++} ++ ++/* Group must be locked when entering this function. Will be unlocked before exiting. */ ++static void mali_group_complete_pp_and_unlock(struct mali_group *group, mali_bool success, mali_bool in_upper_half) ++{ ++ struct mali_pp_job *pp_job_to_return; ++ u32 pp_sub_job_to_return; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_POINTER(group->pp_core); ++ MALI_DEBUG_ASSERT_POINTER(group->pp_running_job); ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ mali_group_post_process_job_pp(group); ++ ++ if (success) { ++ /* Only do soft reset for successful jobs, a full recovery ++ * reset will be done for failed jobs. */ ++ mali_pp_reset_async(group->pp_core); ++ } ++ ++ pp_job_to_return = group->pp_running_job; ++ pp_sub_job_to_return = group->pp_running_sub_job; ++ group->state = MALI_GROUP_STATE_IDLE; ++ group->pp_running_job = NULL; ++ ++ if (!success) { ++ MALI_DEBUG_PRINT(2, ("Mali group: Executing recovery reset due to job failure\n")); ++ mali_group_recovery_reset(group); ++ } else if (_MALI_OSK_ERR_OK != mali_pp_reset_wait(group->pp_core)) { ++ MALI_PRINT_ERROR(("Mali group: Executing recovery reset due to reset failure\n")); ++ mali_group_recovery_reset(group); ++ } ++ ++ /* Return job to user, schedule and unlock group. */ ++ mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, success, in_upper_half); ++} ++ ++/* Group must be locked when entering this function. Will be unlocked before exiting. */ ++static void mali_group_complete_gp_and_unlock(struct mali_group *group, mali_bool success) ++{ ++ struct mali_gp_job *gp_job_to_return; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_POINTER(group->gp_core); ++ MALI_DEBUG_ASSERT_POINTER(group->gp_running_job); ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ mali_group_post_process_job_gp(group, MALI_FALSE); ++ ++ if (success) { ++ /* Only do soft reset for successful jobs, a full recovery ++ * reset will be done for failed jobs. */ ++ mali_gp_reset_async(group->gp_core); ++ } ++ ++ gp_job_to_return = group->gp_running_job; ++ group->state = MALI_GROUP_STATE_IDLE; ++ group->gp_running_job = NULL; ++ ++ if (!success) { ++ MALI_DEBUG_PRINT(2, ("Mali group: Executing recovery reset due to job failure\n")); ++ mali_group_recovery_reset(group); ++ } else if (_MALI_OSK_ERR_OK != mali_gp_reset_wait(group->gp_core)) { ++ MALI_PRINT_ERROR(("Mali group: Executing recovery reset due to reset failure\n")); ++ mali_group_recovery_reset(group); ++ } ++ ++ /* Return job to user, schedule and unlock group. */ ++ mali_gp_scheduler_job_done(group, gp_job_to_return, success); ++} ++ ++void mali_group_abort_gp_job(struct mali_group *group, u32 job_id) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ if (MALI_GROUP_STATE_IDLE == group->state || ++ mali_gp_job_get_id(group->gp_running_job) != job_id) { ++ return; /* No need to cancel or job has already been aborted or completed */ ++ } ++ ++ /* Function will unlock the group, so we need to lock it again */ ++ mali_group_complete_gp_and_unlock(group, MALI_FALSE); ++ mali_group_lock(group); ++} ++ ++static void mali_group_abort_pp_job(struct mali_group *group, u32 job_id) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ if (MALI_GROUP_STATE_IDLE == group->state || ++ mali_pp_job_get_id(group->pp_running_job) != job_id) { ++ return; /* No need to cancel or job has already been aborted or completed */ ++ } ++ ++ mali_group_complete_pp_and_unlock(group, MALI_FALSE, MALI_FALSE); ++ mali_group_lock(group); ++} ++ ++void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session) ++{ ++ struct mali_gp_job *gp_job; ++ struct mali_pp_job *pp_job; ++ u32 gp_job_id = 0; ++ u32 pp_job_id = 0; ++ mali_bool abort_pp = MALI_FALSE; ++ mali_bool abort_gp = MALI_FALSE; ++ ++ mali_group_lock(group); ++ ++ if (mali_group_is_in_virtual(group)) { ++ /* Group is member of a virtual group, don't touch it! */ ++ mali_group_unlock(group); ++ return; ++ } ++ ++ gp_job = group->gp_running_job; ++ pp_job = group->pp_running_job; ++ ++ if ((NULL != gp_job) && (mali_gp_job_get_session(gp_job) == session)) { ++ MALI_DEBUG_PRINT(4, ("Aborting GP job 0x%08x from session 0x%08x\n", gp_job, session)); ++ ++ gp_job_id = mali_gp_job_get_id(gp_job); ++ abort_gp = MALI_TRUE; ++ } ++ ++ if ((NULL != pp_job) && (mali_pp_job_get_session(pp_job) == session)) { ++ MALI_DEBUG_PRINT(4, ("Mali group: Aborting PP job 0x%08x from session 0x%08x\n", pp_job, session)); ++ ++ pp_job_id = mali_pp_job_get_id(pp_job); ++ abort_pp = MALI_TRUE; ++ } ++ ++ if (abort_gp) { ++ mali_group_abort_gp_job(group, gp_job_id); ++ } ++ if (abort_pp) { ++ mali_group_abort_pp_job(group, pp_job_id); ++ } ++ ++ mali_group_remove_session_if_unused(group, session); ++ ++ mali_group_unlock(group); ++} ++ ++struct mali_group *mali_group_get_glob_group(u32 index) ++{ ++ if(mali_global_num_groups > index) { ++ return mali_global_groups[index]; ++ } ++ ++ return NULL; ++} ++ ++u32 mali_group_get_glob_num_groups(void) ++{ ++ return mali_global_num_groups; ++} ++ ++static void mali_group_activate_page_directory(struct mali_group *group, struct mali_session_data *session) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ MALI_DEBUG_PRINT(5, ("Mali group: Activating page directory 0x%08X from session 0x%08X on group 0x%08X\n", mali_session_get_page_directory(session), session, group)); ++ ++ if (group->session != session) { ++ /* Different session than last time, so we need to do some work */ ++ MALI_DEBUG_PRINT(5, ("Mali group: Activate session: %08x previous: %08x on group 0x%08X\n", session, group->session, group)); ++ mali_mmu_activate_page_directory(group->mmu, mali_session_get_page_directory(session)); ++ group->session = session; ++ } else { ++ /* Same session as last time, so no work required */ ++ MALI_DEBUG_PRINT(4, ("Mali group: Activate existing session 0x%08X on group 0x%08X\n", session->page_directory, group)); ++ mali_mmu_zap_tlb_without_stall(group->mmu); ++ } ++} ++ ++static void mali_group_remove_session_if_unused(struct mali_group *group, struct mali_session_data *session) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ if (MALI_GROUP_STATE_IDLE == group->state) { ++ if (group->session == session) { ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_WORKING != group->state); ++ MALI_DEBUG_ASSERT(MALI_TRUE == group->power_is_on); ++ MALI_DEBUG_PRINT(3, ("Mali group: Deactivating unused session 0x%08X on group %08X\n", session, group)); ++ mali_mmu_activate_empty_page_directory(group->mmu); ++ group->session = NULL; ++ } ++ } ++} ++ ++mali_bool mali_group_power_is_on(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++ return group->power_is_on; ++} ++ ++void mali_group_power_on_group(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++ MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state ++ || MALI_GROUP_STATE_IN_VIRTUAL == group->state ++ || MALI_GROUP_STATE_JOINING_VIRTUAL == group->state ++ || MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state ++ || MALI_GROUP_STATE_DISABLED == group->state); ++ ++ MALI_DEBUG_PRINT(3, ("Group %p powered on\n", group)); ++ ++ group->power_is_on = MALI_TRUE; ++} ++ ++void mali_group_power_off_group(struct mali_group *group, mali_bool do_power_change) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_LOCK_HELD(group->lock); ++ MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state ++ || MALI_GROUP_STATE_IN_VIRTUAL == group->state ++ || MALI_GROUP_STATE_JOINING_VIRTUAL == group->state ++ || MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state ++ || MALI_GROUP_STATE_DISABLED == group->state); ++ ++ MALI_DEBUG_PRINT(3, ("Group %p powered off\n", group)); ++ ++ /* It is necessary to set group->session = NULL so that the powered off MMU is not written ++ * to on map/unmap. It is also necessary to set group->power_is_on = MALI_FALSE so that ++ * pending bottom_halves does not access powered off cores. */ ++ ++ group->session = NULL; ++ ++ if (do_power_change) { ++ group->power_is_on = MALI_FALSE; ++ } ++} ++ ++void mali_group_power_on(void) ++{ ++ int i; ++ for (i = 0; i < mali_global_num_groups; i++) { ++ struct mali_group *group = mali_global_groups[i]; ++ ++ mali_group_lock(group); ++ if (MALI_GROUP_STATE_DISABLED == group->state) { ++ MALI_DEBUG_ASSERT(MALI_FALSE == group->power_is_on); ++ } else { ++ mali_group_power_on_group(group); ++ } ++ mali_group_unlock(group); ++ } ++ MALI_DEBUG_PRINT(4, ("Mali Group: power on\n")); ++} ++ ++void mali_group_power_off(mali_bool do_power_change) ++{ ++ int i; ++ ++ for (i = 0; i < mali_global_num_groups; i++) { ++ struct mali_group *group = mali_global_groups[i]; ++ ++ mali_group_lock(group); ++ if (MALI_GROUP_STATE_DISABLED == group->state) { ++ MALI_DEBUG_ASSERT(MALI_FALSE == group->power_is_on); ++ } else { ++ mali_group_power_off_group(group, do_power_change); ++ } ++ mali_group_unlock(group); ++ } ++ MALI_DEBUG_PRINT(4, ("Mali Group: power off\n")); ++} ++ ++static void mali_group_recovery_reset(struct mali_group *group) ++{ ++ _mali_osk_errcode_t err; ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ /* Stop cores, bus stop */ ++ if (NULL != group->pp_core) { ++ mali_pp_stop_bus(group->pp_core); ++ } else { ++ mali_gp_stop_bus(group->gp_core); ++ } ++ ++ /* Flush MMU and clear page fault (if any) */ ++ mali_mmu_activate_fault_flush_page_directory(group->mmu); ++ mali_mmu_page_fault_done(group->mmu); ++ ++ /* Wait for cores to stop bus, then do a hard reset on them */ ++ if (NULL != group->pp_core) { ++ if (mali_group_is_virtual(group)) { ++ struct mali_group *child, *temp; ++ ++ /* Disable the broadcast unit while we do reset directly on the member cores. */ ++ mali_bcast_disable(group->bcast_core); ++ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ mali_pp_stop_bus_wait(child->pp_core); ++ mali_pp_hard_reset(child->pp_core); ++ } ++ ++ mali_bcast_enable(group->bcast_core); ++ } else { ++ mali_pp_stop_bus_wait(group->pp_core); ++ mali_pp_hard_reset(group->pp_core); ++ } ++ } else { ++ mali_gp_stop_bus_wait(group->gp_core); ++ mali_gp_hard_reset(group->gp_core); ++ } ++ ++ /* Reset MMU */ ++ err = mali_mmu_reset(group->mmu); ++ MALI_DEBUG_ASSERT(_MALI_OSK_ERR_OK == err); ++ MALI_IGNORE(err); ++ ++ group->session = NULL; ++} ++ ++#if MALI_STATE_TRACKING ++u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size) ++{ ++ int n = 0; ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "Group: %p\n", group); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tstate: %d\n", group->state); ++ if (group->gp_core) { ++ n += mali_gp_dump_state(group->gp_core, buf + n, size - n); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tGP job: %p\n", group->gp_running_job); ++ } ++ if (group->pp_core) { ++ n += mali_pp_dump_state(group->pp_core, buf + n, size - n); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tPP job: %p, subjob %d \n", ++ group->pp_running_job, group->pp_running_sub_job); ++ } ++ ++ return n; ++} ++#endif ++ ++/* Group must be locked when entering this function. Will be unlocked before exiting. */ ++static void mali_group_mmu_page_fault_and_unlock(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ if (NULL != group->pp_core) { ++ struct mali_pp_job *pp_job_to_return; ++ u32 pp_sub_job_to_return; ++ ++ MALI_DEBUG_ASSERT_POINTER(group->pp_running_job); ++ ++ mali_group_post_process_job_pp(group); ++ ++ pp_job_to_return = group->pp_running_job; ++ pp_sub_job_to_return = group->pp_running_sub_job; ++ group->state = MALI_GROUP_STATE_IDLE; ++ group->pp_running_job = NULL; ++ ++ mali_group_recovery_reset(group); /* This will also clear the page fault itself */ ++ ++ /* Will unlock group. */ ++ mali_pp_scheduler_job_done(group, pp_job_to_return, pp_sub_job_to_return, MALI_FALSE, MALI_FALSE); ++ } else { ++ struct mali_gp_job *gp_job_to_return; ++ ++ MALI_DEBUG_ASSERT_POINTER(group->gp_running_job); ++ ++ mali_group_post_process_job_gp(group, MALI_FALSE); ++ ++ gp_job_to_return = group->gp_running_job; ++ group->state = MALI_GROUP_STATE_IDLE; ++ group->gp_running_job = NULL; ++ ++ mali_group_recovery_reset(group); /* This will also clear the page fault itself */ ++ ++ /* Will unlock group. */ ++ mali_gp_scheduler_job_done(group, gp_job_to_return, MALI_FALSE); ++ } ++} ++ ++_mali_osk_errcode_t mali_group_upper_half_mmu(void * data) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ struct mali_group *group = (struct mali_group *)data; ++ struct mali_mmu_core *mmu = group->mmu; ++ u32 int_stat; ++ ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ if (MALI_FALSE == mali_pm_domain_lock_state(group->pm_domain)) { ++ goto out; ++ } ++#endif ++ ++ /* Check if it was our device which caused the interrupt (we could be sharing the IRQ line) */ ++ int_stat = mali_mmu_get_int_status(mmu); ++ if (0 != int_stat) { ++ struct mali_group *parent = group->parent_group; ++ ++ /* page fault or bus error, we thread them both in the same way */ ++ mali_mmu_mask_all_interrupts(mmu); ++ if (NULL == parent) { ++ _mali_osk_wq_schedule_work(group->bottom_half_work_mmu); ++ } else { ++ _mali_osk_wq_schedule_work(parent->bottom_half_work_mmu); ++ } ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++ ++out: ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ mali_pm_domain_unlock_state(group->pm_domain); ++#endif ++ ++ return err; ++} ++ ++static void mali_group_bottom_half_mmu(void * data) ++{ ++ struct mali_group *group = (struct mali_group *)data; ++ struct mali_mmu_core *mmu = group->mmu; ++ u32 rawstat; ++ MALI_DEBUG_CODE(u32 status); ++ ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ ++ mali_group_lock(group); ++ ++ MALI_DEBUG_ASSERT(NULL == group->parent_group); ++ ++ if ( MALI_FALSE == mali_group_power_is_on(group) ) { ++ MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", mmu->hw_core.description)); ++ mali_group_unlock(group); ++ return; ++ } ++ ++ rawstat = mali_mmu_get_rawstat(mmu); ++ MALI_DEBUG_CODE(status = mali_mmu_get_status(mmu)); ++ ++ MALI_DEBUG_PRINT(4, ("Mali MMU: Bottom half, interrupt 0x%08X, status 0x%08X\n", rawstat, status)); ++ ++ if (rawstat & (MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR)) { ++ /* An actual page fault has occurred. */ ++#ifdef DEBUG ++ u32 fault_address = mali_mmu_get_page_fault_addr(mmu); ++ MALI_DEBUG_PRINT(2,("Mali MMU: Page fault detected at 0x%x from bus id %d of type %s on %s\n", ++ (void*)fault_address, ++ (status >> 6) & 0x1F, ++ (status & 32) ? "write" : "read", ++ mmu->hw_core.description)); ++#endif ++ ++ mali_group_mmu_page_fault_and_unlock(group); ++ return; ++ } ++ ++ mali_group_unlock(group); ++} ++ ++_mali_osk_errcode_t mali_group_upper_half_gp(void *data) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ struct mali_group *group = (struct mali_group *)data; ++ struct mali_gp_core *core = group->gp_core; ++ u32 irq_readout; ++ ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ if (MALI_FALSE == mali_pm_domain_lock_state(group->pm_domain)) { ++ goto out; ++ } ++#endif ++ ++ irq_readout = mali_gp_get_int_stat(core); ++ ++ if (MALIGP2_REG_VAL_IRQ_MASK_NONE != irq_readout) { ++ /* Mask out all IRQs from this core until IRQ is handled */ ++ mali_gp_mask_all_interrupts(core); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0)|MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, irq_readout, 0, 0, 0, 0); ++ ++ /* We do need to handle this in a bottom half */ ++ _mali_osk_wq_schedule_work(group->bottom_half_work_gp); ++ ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++ ++out: ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ mali_pm_domain_unlock_state(group->pm_domain); ++#endif ++ ++ return err; ++} ++ ++static void mali_group_bottom_half_gp(void *data) ++{ ++ struct mali_group *group = (struct mali_group *)data; ++ u32 irq_readout; ++ u32 irq_errors; ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, 0, _mali_osk_get_tid(), MALI_PROFILING_MAKE_EVENT_DATA_CORE_GP(0), 0, 0); ++ ++ mali_group_lock(group); ++ ++ if ( MALI_FALSE == mali_group_power_is_on(group) ) { ++ MALI_PRINT_ERROR(("Mali group: Interrupt bottom half of %s when core is OFF.", mali_gp_get_hw_core_desc(group->gp_core))); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ ++ irq_readout = mali_gp_read_rawstat(group->gp_core); ++ ++ MALI_DEBUG_PRINT(4, ("Mali group: GP bottom half IRQ 0x%08X from core %s\n", irq_readout, mali_gp_get_hw_core_desc(group->gp_core))); ++ ++ if (irq_readout & (MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST)) { ++ u32 core_status = mali_gp_read_core_status(group->gp_core); ++ if (0 == (core_status & MALIGP2_REG_VAL_STATUS_MASK_ACTIVE)) { ++ MALI_DEBUG_PRINT(4, ("Mali group: GP job completed, calling group handler\n")); ++ group->core_timed_out = MALI_FALSE; ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ ++ mali_group_complete_gp_and_unlock(group, MALI_TRUE); ++ return; ++ } ++ } ++ ++ /* ++ * Now lets look at the possible error cases (IRQ indicating error or timeout) ++ * END_CMD_LST, HANG and PLBU_OOM interrupts are not considered error. ++ */ ++ irq_errors = irq_readout & ~(MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST|MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST|MALIGP2_REG_VAL_IRQ_HANG|MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM); ++ if (0 != irq_errors) { ++ MALI_PRINT_ERROR(("Mali group: Unknown interrupt 0x%08X from core %s, aborting job\n", irq_readout, mali_gp_get_hw_core_desc(group->gp_core))); ++ group->core_timed_out = MALI_FALSE; ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ ++ mali_group_complete_gp_and_unlock(group, MALI_FALSE); ++ return; ++ } else if (group->core_timed_out) { /* SW timeout */ ++ group->core_timed_out = MALI_FALSE; ++ if (!_mali_osk_timer_pending(group->timeout_timer) && NULL != group->gp_running_job) { ++ MALI_PRINT(("Mali group: Job %d timed out\n", mali_gp_job_get_id(group->gp_running_job))); ++ ++ mali_group_complete_gp_and_unlock(group, MALI_FALSE); ++ return; ++ } ++ } else if (irq_readout & MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM) { ++ /* GP wants more memory in order to continue. */ ++ MALI_DEBUG_PRINT(3, ("Mali group: PLBU needs more heap memory\n")); ++ ++ group->state = MALI_GROUP_STATE_OOM; ++ mali_group_unlock(group); /* Nothing to do on the HW side, so just release group lock right away */ ++ mali_gp_scheduler_oom(group, group->gp_running_job); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ ++ /* ++ * The only way to get here is if we only got one of two needed END_CMD_LST ++ * interrupts. Enable all but not the complete interrupt that has been ++ * received and continue to run. ++ */ ++ mali_gp_enable_interrupts(group->gp_core, irq_readout & (MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST|MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST)); ++ mali_group_unlock(group); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, 0, _mali_osk_get_tid(), 0, 0, 0); ++} ++ ++static void mali_group_post_process_job_gp(struct mali_group *group, mali_bool suspend) ++{ ++ /* Stop the timeout timer. */ ++ _mali_osk_timer_del_async(group->timeout_timer); ++ ++ if (NULL == group->gp_running_job) { ++ /* Nothing to do */ ++ return; ++ } ++ ++ mali_gp_update_performance_counters(group->gp_core, group->gp_running_job, suspend); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ if (suspend) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), ++ mali_gp_job_get_perf_counter_value0(group->gp_running_job), ++ mali_gp_job_get_perf_counter_value1(group->gp_running_job), ++ mali_gp_job_get_perf_counter_src0(group->gp_running_job) | (mali_gp_job_get_perf_counter_src1(group->gp_running_job) << 8), ++ 0, 0); ++ } else { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP|MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(0), ++ mali_gp_job_get_perf_counter_value0(group->gp_running_job), ++ mali_gp_job_get_perf_counter_value1(group->gp_running_job), ++ mali_gp_job_get_perf_counter_src0(group->gp_running_job) | (mali_gp_job_get_perf_counter_src1(group->gp_running_job) << 8), ++ 0, 0); ++ ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) ++ mali_group_report_l2_cache_counters_per_core(group, 0); ++ } ++#endif ++ ++ mali_gp_job_set_current_heap_addr(group->gp_running_job, ++ mali_gp_read_plbu_alloc_start_addr(group->gp_core)); ++} ++ ++_mali_osk_errcode_t mali_group_upper_half_pp(void *data) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ struct mali_group *group = (struct mali_group *)data; ++ struct mali_pp_core *core = group->pp_core; ++ u32 irq_readout; ++ ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ if (MALI_FALSE == mali_pm_domain_lock_state(group->pm_domain)) { ++ goto out; ++ } ++#endif ++ ++ /* ++ * For Mali-450 there is one particular case we need to watch out for: ++ * ++ * Criteria 1) this function call can be due to a shared interrupt, ++ * and not necessary because this core signaled an interrupt. ++ * Criteria 2) this core is a part of a virtual group, and thus it should ++ * not do any post processing. ++ * Criteria 3) this core has actually indicated that is has completed by ++ * having set raw_stat/int_stat registers to != 0 ++ * ++ * If all this criteria is meet, then we could incorrectly start post ++ * processing on the wrong group object (this should only happen on the ++ * parent group) ++ */ ++#if !defined(MALI_UPPER_HALF_SCHEDULING) ++ if (mali_group_is_in_virtual(group)) { ++ /* ++ * This check is done without the group lock held, which could lead to ++ * a potential race. This is however ok, since we will safely re-check ++ * this with the group lock held at a later stage. This is just an ++ * early out which will strongly benefit shared IRQ systems. ++ */ ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++#endif ++ ++ irq_readout = mali_pp_get_int_stat(core); ++ if (MALI200_REG_VAL_IRQ_MASK_NONE != irq_readout) { ++ /* Mask out all IRQs from this core until IRQ is handled */ ++ mali_pp_mask_all_interrupts(core); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ /* Currently no support for this interrupt event for the virtual PP core */ ++ if (!mali_group_is_virtual(group)) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(core->core_id) | ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT, ++ irq_readout, 0, 0, 0, 0); ++ } ++#endif ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ /* Check if job is complete without errors */ ++ if (MALI200_REG_VAL_IRQ_END_OF_FRAME == irq_readout) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF, ++ 0, 0, MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP: Job completed, calling group handler from upper half\n")); ++ ++ mali_group_lock(group); ++ ++ /* Check if job is complete without errors, again, after taking the group lock */ ++ irq_readout = mali_pp_read_rawstat(core); ++ if (MALI200_REG_VAL_IRQ_END_OF_FRAME != irq_readout) { ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF, ++ 0, 0, MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++ ++ if (mali_group_is_virtual(group)) { ++ u32 status_readout = mali_pp_read_status(group->pp_core); ++ if (status_readout & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE) { ++ MALI_DEBUG_PRINT(6, ("Mali PP: Not all cores in broadcast completed\n")); ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF, ++ 0, 0, MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++ } ++ ++ if (mali_group_is_in_virtual(group)) { ++ /* We're member of a virtual group, so interrupt should be handled by the virtual group */ ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF, ++ 0, 0, MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ err = _MALI_OSK_ERR_FAULT; ++ goto out; ++ } ++ ++ group->core_timed_out = MALI_FALSE; ++ ++ mali_group_complete_pp_and_unlock(group, MALI_TRUE, MALI_TRUE); ++ ++ /* No need to enable interrupts again, since the core will be reset while completing the job */ ++ ++ MALI_DEBUG_PRINT(6, ("Mali PP: Upper half job done\n")); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF, ++ 0, 0, MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++#endif ++ ++ /* We do need to handle this in a bottom half */ ++ _mali_osk_wq_schedule_work(group->bottom_half_work_pp); ++ err = _MALI_OSK_ERR_OK; ++ goto out; ++ } ++ ++out: ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ mali_pm_domain_unlock_state(group->pm_domain); ++#endif ++ ++ return err; ++} ++ ++static void mali_group_bottom_half_pp(void *data) ++{ ++ struct mali_group *group = (struct mali_group *)data; ++ struct mali_pp_core *core = group->pp_core; ++ u32 irq_readout; ++ u32 irq_errors; ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_START | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(core->core_id), 0, 0); ++ ++ mali_group_lock(group); ++ ++ if (mali_group_is_in_virtual(group)) { ++ /* We're member of a virtual group, so interrupt should be handled by the virtual group */ ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ ++ if ( MALI_FALSE == mali_group_power_is_on(group) ) { ++ MALI_PRINT_ERROR(("Interrupt bottom half of %s when core is OFF.", mali_pp_get_hw_core_desc(core))); ++ mali_group_unlock(group); ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ ++ irq_readout = mali_pp_read_rawstat(group->pp_core); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP: Bottom half IRQ 0x%08X from core %s\n", irq_readout, mali_pp_get_hw_core_desc(group->pp_core))); ++ ++ /* Check if job is complete without errors */ ++ if (MALI200_REG_VAL_IRQ_END_OF_FRAME == irq_readout) { ++ if (mali_group_is_virtual(group)) { ++ u32 status_readout = mali_pp_read_status(group->pp_core); ++ ++ if (status_readout & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE && !group->core_timed_out) { ++ MALI_DEBUG_PRINT(6, ("Mali PP: Not all cores in broadcast completed\n")); ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ } ++ ++ if (!group->core_timed_out) { ++ MALI_DEBUG_PRINT(3, ("Mali PP: Job completed, calling group handler\n")); ++ group->core_timed_out = MALI_FALSE; ++ ++ mali_group_complete_pp_and_unlock(group, MALI_TRUE, MALI_FALSE); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ } ++ ++ /* ++ * Now lets look at the possible error cases (IRQ indicating error or timeout) ++ * END_OF_FRAME and HANG interrupts are not considered error. ++ */ ++ irq_errors = irq_readout & ~(MALI200_REG_VAL_IRQ_END_OF_FRAME|MALI200_REG_VAL_IRQ_HANG); ++ if (0 != irq_errors) { ++ MALI_PRINT_ERROR(("Mali PP: Unexpected interrupt 0x%08X from core %s, aborting job\n", ++ irq_readout, mali_pp_get_hw_core_desc(group->pp_core))); ++ group->core_timed_out = MALI_FALSE; ++ ++ mali_group_complete_pp_and_unlock(group, MALI_FALSE, MALI_FALSE); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } else if (group->core_timed_out) { /* SW timeout */ ++ group->core_timed_out = MALI_FALSE; ++ if (!_mali_osk_timer_pending(group->timeout_timer) && NULL != group->pp_running_job) { ++ MALI_PRINT(("Mali PP: Job %d timed out on core %s\n", ++ mali_pp_job_get_id(group->pp_running_job), mali_pp_get_hw_core_desc(core))); ++ ++ mali_group_complete_pp_and_unlock(group, MALI_FALSE, MALI_FALSE); ++ } else { ++ mali_group_unlock(group); ++ } ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++ return; ++ } ++ ++ /* ++ * We should never get here, re-enable interrupts and continue ++ */ ++ if (0 == irq_readout) { ++ MALI_DEBUG_PRINT(3, ("Mali group: No interrupt found on core %s\n", ++ mali_pp_get_hw_core_desc(group->pp_core))); ++ } else { ++ MALI_PRINT_ERROR(("Mali group: Unhandled PP interrupt 0x%08X on %s\n", irq_readout, ++ mali_pp_get_hw_core_desc(group->pp_core))); ++ } ++ mali_pp_enable_interrupts(core); ++ mali_group_unlock(group); ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF, ++ 0, _mali_osk_get_tid(), 0, 0, 0); ++} ++ ++static void mali_group_post_process_job_pp(struct mali_group *group) ++{ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ ++ /* Stop the timeout timer. */ ++ _mali_osk_timer_del_async(group->timeout_timer); ++ ++ if (NULL != group->pp_running_job) { ++ if (MALI_TRUE == mali_group_is_virtual(group)) { ++ struct mali_group *child; ++ struct mali_group *temp; ++ ++ /* update performance counters from each physical pp core within this virtual group */ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ mali_pp_update_performance_counters(group->pp_core, child->pp_core, group->pp_running_job, mali_pp_core_get_id(child->pp_core)); ++ } ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ /* send profiling data per physical core */ ++ _MALI_OSK_LIST_FOREACHENTRY(child, temp, &group->group_list, struct mali_group, group_list) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(child->pp_core))| ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL, ++ mali_pp_job_get_perf_counter_value0(group->pp_running_job, mali_pp_core_get_id(child->pp_core)), ++ mali_pp_job_get_perf_counter_value1(group->pp_running_job, mali_pp_core_get_id(child->pp_core)), ++ mali_pp_job_get_perf_counter_src0(group->pp_running_job, group->pp_running_sub_job) | (mali_pp_job_get_perf_counter_src1(group->pp_running_job, group->pp_running_sub_job) << 8), ++ 0, 0); ++ } ++ if (0 != group->l2_cache_core_ref_count[0]) { ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[0])); ++ } ++ } ++ if (0 != group->l2_cache_core_ref_count[1]) { ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[1])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[1]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[1])); ++ } ++ } ++ ++#endif ++ } else { ++ /* update performance counters for a physical group's pp core */ ++ mali_pp_update_performance_counters(group->pp_core, group->pp_core, group->pp_running_job, group->pp_running_sub_job); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_STOP| ++ MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(mali_pp_core_get_id(group->pp_core))| ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_PHYSICAL, ++ mali_pp_job_get_perf_counter_value0(group->pp_running_job, group->pp_running_sub_job), ++ mali_pp_job_get_perf_counter_value1(group->pp_running_job, group->pp_running_sub_job), ++ mali_pp_job_get_perf_counter_src0(group->pp_running_job, group->pp_running_sub_job) | (mali_pp_job_get_perf_counter_src1(group->pp_running_job, group->pp_running_sub_job) << 8), ++ 0, 0); ++ ++ if ((MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src0(group->l2_cache_core[0])) && ++ (MALI_HW_CORE_NO_COUNTER != mali_l2_cache_core_get_counter_src1(group->l2_cache_core[0]))) { ++ mali_group_report_l2_cache_counters_per_core(group, mali_l2_cache_get_id(group->l2_cache_core[0])); ++ } ++#endif ++ } ++ } ++} ++ ++static void mali_group_timeout(void *data) ++{ ++ struct mali_group *group = (struct mali_group *)data; ++ ++ group->core_timed_out = MALI_TRUE; ++ ++ if (NULL != group->gp_core) { ++ MALI_DEBUG_PRINT(2, ("Mali group: TIMEOUT on %s\n", mali_gp_get_hw_core_desc(group->gp_core))); ++ _mali_osk_wq_schedule_work(group->bottom_half_work_gp); ++ } else { ++ MALI_DEBUG_PRINT(2, ("Mali group: TIMEOUT on %s\n", mali_pp_get_hw_core_desc(group->pp_core))); ++ _mali_osk_wq_schedule_work(group->bottom_half_work_pp); ++ } ++} ++ ++void mali_group_zap_session(struct mali_group *group, struct mali_session_data *session) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ /* Early out - safe even if mutex is not held */ ++ if (group->session != session) return; ++ ++ mali_group_lock(group); ++ ++ mali_group_remove_session_if_unused(group, session); ++ ++ if (group->session == session) { ++ /* The Zap also does the stall and disable_stall */ ++ mali_bool zap_success = mali_mmu_zap_tlb(group->mmu); ++ if (MALI_TRUE != zap_success) { ++ MALI_DEBUG_PRINT(2, ("Mali memory unmap failed. Doing pagefault handling.\n")); ++ ++ mali_group_mmu_page_fault_and_unlock(group); ++ return; ++ } ++ } ++ ++ mali_group_unlock(group); ++} ++ ++#if defined(CONFIG_MALI400_PROFILING) ++static void mali_group_report_l2_cache_counters_per_core(struct mali_group *group, u32 core_num) ++{ ++ u32 source0 = 0; ++ u32 value0 = 0; ++ u32 source1 = 0; ++ u32 value1 = 0; ++ u32 profiling_channel = 0; ++ ++ switch(core_num) { ++ case 0: ++ profiling_channel = MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_EVENT_CHANNEL_GPU | ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L20_COUNTERS; ++ break; ++ case 1: ++ profiling_channel = MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_EVENT_CHANNEL_GPU | ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L21_COUNTERS; ++ break; ++ case 2: ++ profiling_channel = MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_EVENT_CHANNEL_GPU | ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L22_COUNTERS; ++ break; ++ default: ++ profiling_channel = MALI_PROFILING_EVENT_TYPE_SINGLE | ++ MALI_PROFILING_EVENT_CHANNEL_GPU | ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L20_COUNTERS; ++ break; ++ } ++ ++ if (0 == core_num) { ++ mali_l2_cache_core_get_counter_values(group->l2_cache_core[0], &source0, &value0, &source1, &value1); ++ } ++ if (1 == core_num) { ++ if (1 == mali_l2_cache_get_id(group->l2_cache_core[0])) { ++ mali_l2_cache_core_get_counter_values(group->l2_cache_core[0], &source0, &value0, &source1, &value1); ++ } else if (1 == mali_l2_cache_get_id(group->l2_cache_core[1])) { ++ mali_l2_cache_core_get_counter_values(group->l2_cache_core[1], &source0, &value0, &source1, &value1); ++ } ++ } ++ if (2 == core_num) { ++ if (2 == mali_l2_cache_get_id(group->l2_cache_core[0])) { ++ mali_l2_cache_core_get_counter_values(group->l2_cache_core[0], &source0, &value0, &source1, &value1); ++ } else if (2 == mali_l2_cache_get_id(group->l2_cache_core[1])) { ++ mali_l2_cache_core_get_counter_values(group->l2_cache_core[1], &source0, &value0, &source1, &value1); ++ } ++ } ++ ++ _mali_osk_profiling_add_event(profiling_channel, source1 << 8 | source0, value0, value1, 0, 0); ++} ++#endif /* #if defined(CONFIG_MALI400_PROFILING) */ ++ ++mali_bool mali_group_is_enabled(struct mali_group *group) ++{ ++ mali_bool enabled = MALI_TRUE; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ mali_group_lock(group); ++ if (MALI_GROUP_STATE_DISABLED == group->state) { ++ enabled = MALI_FALSE; ++ } ++ mali_group_unlock(group); ++ ++ return enabled; ++} ++ ++void mali_group_enable(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT( NULL != mali_group_get_pp_core(group) ++ || NULL != mali_group_get_gp_core(group)); ++ ++ if (NULL != mali_group_get_pp_core(group)) { ++ mali_pp_scheduler_enable_group(group); ++ } else { ++ mali_gp_scheduler_enable_group(group); ++ } ++} ++ ++void mali_group_disable(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT( NULL != mali_group_get_pp_core(group) ++ || NULL != mali_group_get_gp_core(group)); ++ ++ if (NULL != mali_group_get_pp_core(group)) { ++ mali_pp_scheduler_disable_group(group); ++ } else { ++ mali_gp_scheduler_disable_group(group); ++ } ++} ++ ++static struct mali_pm_domain* mali_group_get_l2_domain(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT(NULL == group->l2_cache_core[1]); ++ ++ /* l2_cache_core[0] stores the related l2 domain */ ++ return group->l2_cache_core[0]->pm_domain; ++} ++ ++void mali_group_get_pm_domain_ref(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ /* Get group used l2 domain ref */ ++ mali_pm_domain_ref_get(mali_group_get_l2_domain(group)); ++ /* Get group used core domain ref */ ++ mali_pm_domain_ref_get(group->pm_domain); ++} ++ ++void mali_group_put_pm_domain_ref(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ /* Put group used core domain ref */ ++ mali_pm_domain_ref_put(group->pm_domain); ++ /* Put group used l2 domain ref */ ++ mali_pm_domain_ref_put(mali_group_get_l2_domain(group)); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.h +new file mode 100644 +index 0000000..269403f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_group.h +@@ -0,0 +1,309 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_GROUP_H__ ++#define __MALI_GROUP_H__ ++ ++#include "linux/jiffies.h" ++#include "mali_osk.h" ++#include "mali_l2_cache.h" ++#include "mali_mmu.h" ++#include "mali_gp.h" ++#include "mali_pp.h" ++#include "mali_session.h" ++ ++/** ++ * @brief Default max runtime [ms] for a core job - used by timeout timers ++ */ ++#define MALI_MAX_JOB_RUNTIME_DEFAULT 4000 ++ ++/** @brief A mali group object represents a MMU and a PP and/or a GP core. ++ * ++ */ ++#define MALI_MAX_NUMBER_OF_GROUPS 10 ++ ++enum mali_group_core_state { ++ MALI_GROUP_STATE_IDLE, ++ MALI_GROUP_STATE_WORKING, ++ MALI_GROUP_STATE_OOM, ++ MALI_GROUP_STATE_IN_VIRTUAL, ++ MALI_GROUP_STATE_JOINING_VIRTUAL, ++ MALI_GROUP_STATE_LEAVING_VIRTUAL, ++ MALI_GROUP_STATE_DISABLED, ++}; ++ ++/* Forward declaration from mali_pm_domain.h */ ++struct mali_pm_domain; ++ ++/** ++ * The structure represents a render group ++ * A render group is defined by all the cores that share the same Mali MMU ++ */ ++ ++struct mali_group { ++ struct mali_mmu_core *mmu; ++ struct mali_session_data *session; ++ ++ mali_bool power_is_on; ++ enum mali_group_core_state state; ++ ++ struct mali_gp_core *gp_core; ++ struct mali_gp_job *gp_running_job; ++ ++ struct mali_pp_core *pp_core; ++ struct mali_pp_job *pp_running_job; ++ u32 pp_running_sub_job; ++ ++ struct mali_l2_cache_core *l2_cache_core[2]; ++ u32 l2_cache_core_ref_count[2]; ++ ++ struct mali_dlbu_core *dlbu_core; ++ struct mali_bcast_unit *bcast_core; ++ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_t *lock; ++#else ++ _mali_osk_spinlock_t *lock; ++#endif ++ ++ _mali_osk_list_t pp_scheduler_list; ++ ++ /* List used for virtual groups. For a virtual group, the list represents the ++ * head element. */ ++ _mali_osk_list_t group_list; ++ ++ struct mali_group *pm_domain_list; ++ struct mali_pm_domain *pm_domain; ++ ++ /* Parent virtual group (if any) */ ++ struct mali_group *parent_group; ++ ++ _mali_osk_wq_work_t *bottom_half_work_mmu; ++ _mali_osk_wq_work_t *bottom_half_work_gp; ++ _mali_osk_wq_work_t *bottom_half_work_pp; ++ ++ _mali_osk_timer_t *timeout_timer; ++ mali_bool core_timed_out; ++}; ++ ++/** @brief Create a new Mali group object ++ * ++ * @param cluster Pointer to the cluster to which the group is connected. ++ * @param mmu Pointer to the MMU that defines this group ++ * @return A pointer to a new group object ++ */ ++struct mali_group *mali_group_create(struct mali_l2_cache_core *core, ++ struct mali_dlbu_core *dlbu, ++ struct mali_bcast_unit *bcast); ++ ++_mali_osk_errcode_t mali_group_add_mmu_core(struct mali_group *group, struct mali_mmu_core* mmu_core); ++void mali_group_remove_mmu_core(struct mali_group *group); ++ ++_mali_osk_errcode_t mali_group_add_gp_core(struct mali_group *group, struct mali_gp_core* gp_core); ++void mali_group_remove_gp_core(struct mali_group *group); ++ ++_mali_osk_errcode_t mali_group_add_pp_core(struct mali_group *group, struct mali_pp_core* pp_core); ++void mali_group_remove_pp_core(struct mali_group *group); ++ ++void mali_group_set_pm_domain(struct mali_group *group, struct mali_pm_domain *domain); ++ ++void mali_group_delete(struct mali_group *group); ++ ++/** @brief Virtual groups */ ++void mali_group_add_group(struct mali_group *parent, struct mali_group *child, mali_bool update_hw); ++void mali_group_remove_group(struct mali_group *parent, struct mali_group *child); ++struct mali_group *mali_group_acquire_group(struct mali_group *parent); ++ ++MALI_STATIC_INLINE mali_bool mali_group_is_virtual(struct mali_group *group) ++{ ++#if defined(CONFIG_MALI450) ++ return (NULL != group->dlbu_core); ++#else ++ return MALI_FALSE; ++#endif ++} ++ ++/** @brief Check if a group is considered as part of a virtual group ++ * ++ * @note A group is considered to be "part of" a virtual group also during the transition ++ * in to / out of the virtual group. ++ */ ++MALI_STATIC_INLINE mali_bool mali_group_is_in_virtual(struct mali_group *group) ++{ ++#if defined(CONFIG_MALI450) ++ return (MALI_GROUP_STATE_IN_VIRTUAL == group->state || ++ MALI_GROUP_STATE_JOINING_VIRTUAL == group->state || ++ MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state); ++#else ++ return MALI_FALSE; ++#endif ++} ++ ++/** @brief Reset group ++ * ++ * This function will reset the entire group, including all the cores present in the group. ++ * ++ * @param group Pointer to the group to reset ++ */ ++void mali_group_reset(struct mali_group *group); ++ ++/** @brief Zap MMU TLB on all groups ++ * ++ * Zap TLB on group if \a session is active. ++ */ ++void mali_group_zap_session(struct mali_group* group, struct mali_session_data *session); ++ ++/** @brief Get pointer to GP core object ++ */ ++struct mali_gp_core* mali_group_get_gp_core(struct mali_group *group); ++ ++/** @brief Get pointer to PP core object ++ */ ++struct mali_pp_core* mali_group_get_pp_core(struct mali_group *group); ++ ++/** @brief Lock group object ++ * ++ * Most group functions will lock the group object themselves. The expection is ++ * the group_bottom_half which requires the group to be locked on entry. ++ * ++ * @param group Pointer to group to lock ++ */ ++void mali_group_lock(struct mali_group *group); ++ ++/** @brief Unlock group object ++ * ++ * @param group Pointer to group to unlock ++ */ ++void mali_group_unlock(struct mali_group *group); ++#ifdef DEBUG ++void mali_group_assert_locked(struct mali_group *group); ++#define MALI_ASSERT_GROUP_LOCKED(group) mali_group_assert_locked(group) ++#else ++#define MALI_ASSERT_GROUP_LOCKED(group) ++#endif ++ ++/** @brief Start GP job ++ */ ++void mali_group_start_gp_job(struct mali_group *group, struct mali_gp_job *job); ++/** @brief Start fragment of PP job ++ */ ++void mali_group_start_pp_job(struct mali_group *group, struct mali_pp_job *job, u32 sub_job); ++ ++/** @brief Resume GP job that suspended waiting for more heap memory ++ */ ++struct mali_gp_job *mali_group_resume_gp_with_new_heap(struct mali_group *group, u32 job_id, u32 start_addr, u32 end_addr); ++/** @brief Abort GP job ++ * ++ * Used to abort suspended OOM jobs when user space failed to allocte more memory. ++ */ ++void mali_group_abort_gp_job(struct mali_group *group, u32 job_id); ++/** @brief Abort all GP jobs from \a session ++ * ++ * Used on session close when terminating all running and queued jobs from \a session. ++ */ ++void mali_group_abort_session(struct mali_group *group, struct mali_session_data *session); ++ ++mali_bool mali_group_power_is_on(struct mali_group *group); ++void mali_group_power_on_group(struct mali_group *group); ++void mali_group_power_off_group(struct mali_group *group, mali_bool power_status); ++void mali_group_power_on(void); ++ ++/** @brief Prepare group for power off ++ * ++ * Update the group's state and prepare for the group to be powered off. ++ * ++ * If do_power_change is MALI_FALSE group session will be set to NULL so that ++ * no more activity will happen to this group, but the power state flag will be ++ * left unchanged. ++ * ++ * @do_power_change MALI_TRUE if power status is to be updated ++ */ ++void mali_group_power_off(mali_bool do_power_change); ++ ++struct mali_group *mali_group_get_glob_group(u32 index); ++u32 mali_group_get_glob_num_groups(void); ++ ++u32 mali_group_dump_state(struct mali_group *group, char *buf, u32 size); ++ ++/* MMU-related functions */ ++_mali_osk_errcode_t mali_group_upper_half_mmu(void * data); ++ ++/* GP-related functions */ ++_mali_osk_errcode_t mali_group_upper_half_gp(void *data); ++ ++/* PP-related functions */ ++_mali_osk_errcode_t mali_group_upper_half_pp(void *data); ++ ++/** @brief Check if group is enabled ++ * ++ * @param group group to check ++ * @return MALI_TRUE if enabled, MALI_FALSE if not ++ */ ++mali_bool mali_group_is_enabled(struct mali_group *group); ++ ++/** @brief Enable group ++ * ++ * An enabled job is put on the idle scheduler list and can be used to handle jobs. Does nothing if ++ * group is already enabled. ++ * ++ * @param group group to enable ++ */ ++void mali_group_enable(struct mali_group *group); ++ ++/** @brief Disable group ++ * ++ * A disabled group will no longer be used by the scheduler. If part of a virtual group, the group ++ * will be removed before being disabled. Cores part of a disabled group is safe to power down. ++ * ++ * @param group group to disable ++ */ ++void mali_group_disable(struct mali_group *group); ++ ++MALI_STATIC_INLINE mali_bool mali_group_virtual_disable_if_empty(struct mali_group *group) ++{ ++ mali_bool empty = MALI_FALSE; ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT(mali_group_is_virtual(group)); ++ ++ if (_mali_osk_list_empty(&group->group_list)) { ++ group->state = MALI_GROUP_STATE_DISABLED; ++ group->session = NULL; ++ ++ empty = MALI_TRUE; ++ } ++ ++ return empty; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_group_virtual_enable_if_empty(struct mali_group *group) ++{ ++ mali_bool empty = MALI_FALSE; ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT(mali_group_is_virtual(group)); ++ ++ if (_mali_osk_list_empty(&group->group_list)) { ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state); ++ ++ group->state = MALI_GROUP_STATE_IDLE; ++ ++ empty = MALI_TRUE; ++ } ++ ++ return empty; ++} ++ ++/* Get group used l2 domain and core domain ref */ ++void mali_group_get_pm_domain_ref(struct mali_group *group); ++/* Put group used l2 domain and core domain ref */ ++void mali_group_put_pm_domain_ref(struct mali_group *group); ++ ++#endif /* __MALI_GROUP_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.c +new file mode 100644 +index 0000000..f873420 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.c +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_hw_core.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_osk_mali.h" ++ ++_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size) ++{ ++ core->phys_addr = resource->base; ++ core->phys_offset = resource->base - _mali_osk_resource_base_address(); ++ core->description = resource->description; ++ core->size = reg_size; ++ ++ MALI_DEBUG_ASSERT(core->phys_offset < core->phys_addr); ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_mem_reqregion(core->phys_addr, core->size, core->description)) { ++ core->mapped_registers = _mali_osk_mem_mapioregion(core->phys_addr, core->size, core->description); ++ if (NULL != core->mapped_registers) { ++ return _MALI_OSK_ERR_OK; ++ } else { ++ MALI_PRINT_ERROR(("Failed to map memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); ++ } ++ _mali_osk_mem_unreqregion(core->phys_addr, core->size); ++ } else { ++ MALI_PRINT_ERROR(("Failed to request memory region for core %s at phys_addr 0x%08X\n", core->description, core->phys_addr)); ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++void mali_hw_core_delete(struct mali_hw_core *core) ++{ ++ _mali_osk_mem_unmapioregion(core->phys_addr, core->size, core->mapped_registers); ++ core->mapped_registers = NULL; ++ _mali_osk_mem_unreqregion(core->phys_addr, core->size); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.h +new file mode 100644 +index 0000000..d2c44a9 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_hw_core.h +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_HW_CORE_H__ ++#define __MALI_HW_CORE_H__ ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++/** ++ * The common parts for all Mali HW cores (GP, PP, MMU, L2 and PMU) ++ * This struct is embedded inside all core specific structs. ++ */ ++struct mali_hw_core { ++ u32 phys_addr; /**< Physical address of the registers */ ++ u32 phys_offset; /**< Offset from start of Mali to registers */ ++ u32 size; /**< Size of registers */ ++ mali_io_address mapped_registers; /**< Virtual mapping of the registers */ ++ const char* description; /**< Name of unit (as specified in device configuration) */ ++}; ++ ++#define MALI_REG_POLL_COUNT_FAST 1000 ++#define MALI_REG_POLL_COUNT_SLOW 1000000 ++ ++_mali_osk_errcode_t mali_hw_core_create(struct mali_hw_core *core, const _mali_osk_resource_t *resource, u32 reg_size); ++void mali_hw_core_delete(struct mali_hw_core *core); ++ ++MALI_STATIC_INLINE u32 mali_hw_core_register_read(struct mali_hw_core *core, u32 relative_address) ++{ ++ u32 read_val; ++ read_val = _mali_osk_mem_ioread32(core->mapped_registers, relative_address); ++ MALI_DEBUG_PRINT(6, ("register_read for core %s, relative addr=0x%04X, val=0x%08X\n", ++ core->description, relative_address, read_val)); ++ return read_val; ++} ++ ++MALI_STATIC_INLINE void mali_hw_core_register_write_relaxed(struct mali_hw_core *core, u32 relative_address, u32 new_val) ++{ ++ MALI_DEBUG_PRINT(6, ("register_write_relaxed for core %s, relative addr=0x%04X, val=0x%08X\n", ++ core->description, relative_address, new_val)); ++ _mali_osk_mem_iowrite32_relaxed(core->mapped_registers, relative_address, new_val); ++} ++ ++/* Conditionally write a register. ++ * The register will only be written if the new value is different from the old_value. ++ * If the new value is different, the old value will also be updated */ ++MALI_STATIC_INLINE void mali_hw_core_register_write_relaxed_conditional(struct mali_hw_core *core, u32 relative_address, u32 new_val, const u32 old_val) ++{ ++ MALI_DEBUG_PRINT(6, ("register_write_relaxed for core %s, relative addr=0x%04X, val=0x%08X\n", ++ core->description, relative_address, new_val)); ++ if(old_val != new_val) { ++ _mali_osk_mem_iowrite32_relaxed(core->mapped_registers, relative_address, new_val); ++ } ++} ++ ++ ++MALI_STATIC_INLINE void mali_hw_core_register_write(struct mali_hw_core *core, u32 relative_address, u32 new_val) ++{ ++ MALI_DEBUG_PRINT(6, ("register_write for core %s, relative addr=0x%04X, val=0x%08X\n", ++ core->description, relative_address, new_val)); ++ _mali_osk_mem_iowrite32(core->mapped_registers, relative_address, new_val); ++} ++ ++MALI_STATIC_INLINE void mali_hw_core_register_write_array_relaxed(struct mali_hw_core *core, u32 relative_address, u32 *write_array, u32 nr_of_regs) ++{ ++ u32 i; ++ MALI_DEBUG_PRINT(6, ("register_write_array: for core %s, relative addr=0x%04X, nr of regs=%u\n", ++ core->description,relative_address, nr_of_regs)); ++ ++ /* Do not use burst writes against the registers */ ++ for (i = 0; i< nr_of_regs; i++) { ++ mali_hw_core_register_write_relaxed(core, relative_address + i*4, write_array[i]); ++ } ++} ++ ++/* Conditionally write a set of registers. ++ * The register will only be written if the new value is different from the old_value. ++ * If the new value is different, the old value will also be updated */ ++MALI_STATIC_INLINE void mali_hw_core_register_write_array_relaxed_conditional(struct mali_hw_core *core, u32 relative_address, u32 *write_array, u32 nr_of_regs, const u32* old_array) ++{ ++ u32 i; ++ MALI_DEBUG_PRINT(6, ("register_write_array: for core %s, relative addr=0x%04X, nr of regs=%u\n", ++ core->description,relative_address, nr_of_regs)); ++ ++ /* Do not use burst writes against the registers */ ++ for (i = 0; i< nr_of_regs; i++) { ++ if(old_array[i] != write_array[i]) { ++ mali_hw_core_register_write_relaxed(core, relative_address + i*4, write_array[i]); ++ } ++ } ++} ++ ++#endif /* __MALI_HW_CORE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_common.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_common.h +new file mode 100644 +index 0000000..fe57539 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_common.h +@@ -0,0 +1,175 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_COMMON_H__ ++#define __MALI_KERNEL_COMMON_H__ ++ ++#include "mali_osk.h" ++ ++/* Make sure debug is defined when it should be */ ++#ifndef DEBUG ++#if defined(_DEBUG) ++#define DEBUG ++#endif ++#endif ++ ++/* The file include several useful macros for error checking, debugging and printing. ++ * - MALI_PRINTF(...) Do not use this function: Will be included in Release builds. ++ * - MALI_DEBUG_PRINT(nr, (X) ) Prints the second argument if nr<=MALI_DEBUG_LEVEL. ++ * - MALI_DEBUG_ERROR( (X) ) Prints an errortext, a source trace, and the given error message. ++ * - MALI_DEBUG_ASSERT(exp,(X)) If the asserted expr is false, the program will exit. ++ * - MALI_DEBUG_ASSERT_POINTER(pointer) Triggers if the pointer is a zero pointer. ++ * - MALI_DEBUG_CODE( X ) The code inside the macro is only compiled in Debug builds. ++ * ++ * The (X) means that you must add an extra parenthesis around the argumentlist. ++ * ++ * The printf function: MALI_PRINTF(...) is routed to _mali_osk_debugmsg ++ * ++ * Suggested range for the DEBUG-LEVEL is [1:6] where ++ * [1:2] Is messages with highest priority, indicate possible errors. ++ * [3:4] Is messages with medium priority, output important variables. ++ * [5:6] Is messages with low priority, used during extensive debugging. ++ */ ++ ++/** ++* Fundamental error macro. Reports an error code. This is abstracted to allow us to ++* easily switch to a different error reporting method if we want, and also to allow ++* us to search for error returns easily. ++* ++* Note no closing semicolon - this is supplied in typical usage: ++* ++* MALI_ERROR(MALI_ERROR_OUT_OF_MEMORY); ++*/ ++#define MALI_ERROR(error_code) return (error_code) ++ ++/** ++ * Basic error macro, to indicate success. ++ * Note no closing semicolon - this is supplied in typical usage: ++ * ++ * MALI_SUCCESS; ++ */ ++#define MALI_SUCCESS MALI_ERROR(_MALI_OSK_ERR_OK) ++ ++/** ++ * Basic error macro. This checks whether the given condition is true, and if not returns ++ * from this function with the supplied error code. This is a macro so that we can override it ++ * for stress testing. ++ * ++ * Note that this uses the do-while-0 wrapping to ensure that we don't get problems with dangling ++ * else clauses. Note also no closing semicolon - this is supplied in typical usage: ++ * ++ * MALI_CHECK((p!=NULL), ERROR_NO_OBJECT); ++ */ ++#define MALI_CHECK(condition, error_code) do { if(!(condition)) MALI_ERROR(error_code); } while(0) ++ ++/** ++ * Error propagation macro. If the expression given is anything other than _MALI_OSK_NO_ERROR, ++ * then the value is returned from the enclosing function as an error code. This effectively ++ * acts as a guard clause, and propagates error values up the call stack. This uses a ++ * temporary value to ensure that the error expression is not evaluated twice. ++ * If the counter for forcing a failure has been set using _mali_force_error, this error will be ++ * returned without evaluating the expression in MALI_CHECK_NO_ERROR ++ */ ++#define MALI_CHECK_NO_ERROR(expression) \ ++ do { _mali_osk_errcode_t _check_no_error_result=(expression); \ ++ if(_check_no_error_result != _MALI_OSK_ERR_OK) \ ++ MALI_ERROR(_check_no_error_result); \ ++ } while(0) ++ ++/** ++ * Pointer check macro. Checks non-null pointer. ++ */ ++#define MALI_CHECK_NON_NULL(pointer, error_code) MALI_CHECK( ((pointer)!=NULL), (error_code) ) ++ ++/** ++ * Error macro with goto. This checks whether the given condition is true, and if not jumps ++ * to the specified label using a goto. The label must therefore be local to the function in ++ * which this macro appears. This is most usually used to execute some clean-up code before ++ * exiting with a call to ERROR. ++ * ++ * Like the other macros, this is a macro to allow us to override the condition if we wish, ++ * e.g. to force an error during stress testing. ++ */ ++#define MALI_CHECK_GOTO(condition, label) do { if(!(condition)) goto label; } while(0) ++ ++/** ++ * Explicitly ignore a parameter passed into a function, to suppress compiler warnings. ++ * Should only be used with parameter names. ++ */ ++#define MALI_IGNORE(x) x=x ++ ++#define MALI_PRINTF(args) _mali_osk_dbgmsg args; ++ ++#define MALI_PRINT_ERROR(args) do{ \ ++ MALI_PRINTF(("Mali: ERR: %s\n" ,__FILE__)); \ ++ MALI_PRINTF((" %s()%4d\n ", __FUNCTION__, __LINE__)) ; \ ++ MALI_PRINTF(args); \ ++ MALI_PRINTF(("\n")); \ ++ } while(0) ++ ++#define MALI_PRINT(args) do{ \ ++ MALI_PRINTF(("Mali: ")); \ ++ MALI_PRINTF(args); \ ++ } while (0) ++ ++#ifdef DEBUG ++#ifndef mali_debug_level ++extern int mali_debug_level; ++#endif ++ ++#define MALI_DEBUG_CODE(code) code ++#define MALI_DEBUG_PRINT(level, args) do { \ ++ if((level) <= mali_debug_level)\ ++ {MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); } \ ++ } while (0) ++ ++#define MALI_DEBUG_PRINT_ERROR(args) MALI_PRINT_ERROR(args) ++ ++#define MALI_DEBUG_PRINT_IF(level,condition,args) \ ++ if((condition)&&((level) <= mali_debug_level))\ ++ {MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); } ++ ++#define MALI_DEBUG_PRINT_ELSE(level, args)\ ++ else if((level) <= mali_debug_level)\ ++ { MALI_PRINTF(("Mali<" #level ">: ")); MALI_PRINTF(args); } ++ ++/** ++ * @note these variants of DEBUG ASSERTS will cause a debugger breakpoint ++ * to be entered (see _mali_osk_break() ). An alternative would be to call ++ * _mali_osk_abort(), on OSs that support it. ++ */ ++#define MALI_DEBUG_PRINT_ASSERT(condition, args) do {if( !(condition)) { MALI_PRINT_ERROR(args); _mali_osk_break(); } } while(0) ++#define MALI_DEBUG_ASSERT_POINTER(pointer) do {if( (pointer)== NULL) {MALI_PRINT_ERROR(("NULL pointer " #pointer)); _mali_osk_break();} } while(0) ++#define MALI_DEBUG_ASSERT(condition) do {if( !(condition)) {MALI_PRINT_ERROR(("ASSERT failed: " #condition )); _mali_osk_break();} } while(0) ++ ++#else /* DEBUG */ ++ ++#define MALI_DEBUG_CODE(code) ++#define MALI_DEBUG_PRINT(string,args) do {} while(0) ++#define MALI_DEBUG_PRINT_ERROR(args) do {} while(0) ++#define MALI_DEBUG_PRINT_IF(level,condition,args) do {} while(0) ++#define MALI_DEBUG_PRINT_ELSE(level,condition,args) do {} while(0) ++#define MALI_DEBUG_PRINT_ASSERT(condition,args) do {} while(0) ++#define MALI_DEBUG_ASSERT_POINTER(pointer) do {} while(0) ++#define MALI_DEBUG_ASSERT(condition) do {} while(0) ++ ++#endif /* DEBUG */ ++ ++/** ++ * variables from user space cannot be dereferenced from kernel space; tagging them ++ * with __user allows the GCC compiler to generate a warning. Other compilers may ++ * not support this so we define it here as an empty macro if the compiler doesn't ++ * define it. ++ */ ++#ifndef __user ++#define __user ++#endif ++ ++#endif /* __MALI_KERNEL_COMMON_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.c +new file mode 100644 +index 0000000..e099424 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.c +@@ -0,0 +1,1399 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_ukk.h" ++#include "mali_kernel_core.h" ++#include "mali_memory.h" ++#include "mali_mem_validation.h" ++#include "mali_mmu.h" ++#include "mali_mmu_page_directory.h" ++#include "mali_dlbu.h" ++#include "mali_broadcast.h" ++#include "mali_gp.h" ++#include "mali_pp.h" ++#include "mali_gp_scheduler.h" ++#include "mali_pp_scheduler.h" ++#include "mali_pp_job.h" ++#include "mali_group.h" ++#include "mali_pm.h" ++#include "mali_pmu.h" ++#include "mali_scheduler.h" ++#include "mali_kernel_utilization.h" ++#include "mali_l2_cache.h" ++#include "mali_dma.h" ++#include "mali_timeline.h" ++#include "mali_soft_job.h" ++#include "mali_pm_domain.h" ++#if defined(CONFIG_MALI400_PROFILING) ++#include "mali_osk_profiling.h" ++#endif ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++#include "mali_profiling_internal.h" ++#endif ++ ++ ++/* Mali GPU memory. Real values come from module parameter or from device specific data */ ++unsigned int mali_dedicated_mem_start = 0; ++unsigned int mali_dedicated_mem_size = 0; ++unsigned int mali_shared_mem_size = 0; ++ ++/* Frame buffer memory to be accessible by Mali GPU */ ++int mali_fb_start = 0; ++int mali_fb_size = 0; ++ ++/* Mali max job runtime */ ++extern int mali_max_job_runtime; ++ ++/** Start profiling from module load? */ ++int mali_boot_profiling = 0; ++ ++/** Limits for the number of PP cores behind each L2 cache. */ ++int mali_max_pp_cores_group_1 = 0xFF; ++int mali_max_pp_cores_group_2 = 0xFF; ++ ++int mali_inited_pp_cores_group_1 = 0; ++int mali_inited_pp_cores_group_2 = 0; ++ ++static _mali_product_id_t global_product_id = _MALI_PRODUCT_ID_UNKNOWN; ++static u32 global_gpu_base_address = 0; ++static u32 global_gpu_major_version = 0; ++static u32 global_gpu_minor_version = 0; ++ ++mali_bool mali_gpu_class_is_mali450 = MALI_FALSE; ++ ++static _mali_osk_errcode_t mali_set_global_gpu_base_address(void) ++{ ++ global_gpu_base_address = _mali_osk_resource_base_address(); ++ if (0 == global_gpu_base_address) { ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static u32 mali_get_bcast_id(_mali_osk_resource_t *resource_pp) ++{ ++ switch (resource_pp->base - global_gpu_base_address) { ++ case 0x08000: ++ case 0x20000: /* fall-through for aliased mapping */ ++ return 0x01; ++ case 0x0A000: ++ case 0x22000: /* fall-through for aliased mapping */ ++ return 0x02; ++ case 0x0C000: ++ case 0x24000: /* fall-through for aliased mapping */ ++ return 0x04; ++ case 0x0E000: ++ case 0x26000: /* fall-through for aliased mapping */ ++ return 0x08; ++ case 0x28000: ++ return 0x10; ++ case 0x2A000: ++ return 0x20; ++ case 0x2C000: ++ return 0x40; ++ case 0x2E000: ++ return 0x80; ++ default: ++ return 0; ++ } ++} ++ ++static _mali_osk_errcode_t mali_parse_product_info(void) ++{ ++ /* ++ * Mali-200 has the PP core first, while Mali-300, Mali-400 and Mali-450 have the GP core first. ++ * Look at the version register for the first PP core in order to determine the GPU HW revision. ++ */ ++ ++ u32 first_pp_offset; ++ _mali_osk_resource_t first_pp_resource; ++ ++ /* Find out where the first PP core is located */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x8000, NULL)) { ++ /* Mali-300/400/450 */ ++ first_pp_offset = 0x8000; ++ } else { ++ /* Mali-200 */ ++ first_pp_offset = 0x0000; ++ } ++ ++ /* Find the first PP core resource (again) */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + first_pp_offset, &first_pp_resource)) { ++ /* Create a dummy PP object for this core so that we can read the version register */ ++ struct mali_group *group = mali_group_create(NULL, NULL, NULL); ++ if (NULL != group) { ++ struct mali_pp_core *pp_core = mali_pp_create(&first_pp_resource, group, MALI_FALSE, mali_get_bcast_id(&first_pp_resource)); ++ if (NULL != pp_core) { ++ u32 pp_version = mali_pp_core_get_version(pp_core); ++ mali_group_delete(group); ++ ++ global_gpu_major_version = (pp_version >> 8) & 0xFF; ++ global_gpu_minor_version = pp_version & 0xFF; ++ ++ switch (pp_version >> 16) { ++ case MALI200_PP_PRODUCT_ID: ++ global_product_id = _MALI_PRODUCT_ID_MALI200; ++ MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-200 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); ++ MALI_PRINT_ERROR(("Mali-200 is not supported by this driver.\n")); ++ _mali_osk_abort(); ++ break; ++ case MALI300_PP_PRODUCT_ID: ++ global_product_id = _MALI_PRODUCT_ID_MALI300; ++ MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-300 r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); ++ break; ++ case MALI400_PP_PRODUCT_ID: ++ global_product_id = _MALI_PRODUCT_ID_MALI400; ++ MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-400 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); ++ break; ++ case MALI450_PP_PRODUCT_ID: ++ global_product_id = _MALI_PRODUCT_ID_MALI450; ++ MALI_DEBUG_PRINT(2, ("Found Mali GPU Mali-450 MP r%up%u\n", global_gpu_major_version, global_gpu_minor_version)); ++ break; ++ default: ++ MALI_DEBUG_PRINT(2, ("Found unknown Mali GPU (r%up%u)\n", global_gpu_major_version, global_gpu_minor_version)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++ } else { ++ MALI_PRINT_ERROR(("Failed to create initial PP object\n")); ++ } ++ } else { ++ MALI_PRINT_ERROR(("Failed to create initial group object\n")); ++ } ++ } else { ++ MALI_PRINT_ERROR(("First PP core not specified in config file\n")); ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++ ++static void mali_resource_count(u32 *pp_count, u32 *l2_count) ++{ ++ *pp_count = 0; ++ *l2_count = 0; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x08000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0A000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0C000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0E000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x28000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2A000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2C000, NULL)) { ++ ++(*pp_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2E000, NULL)) { ++ ++(*pp_count); ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x1000, NULL)) { ++ ++(*l2_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x10000, NULL)) { ++ ++(*l2_count); ++ } ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x11000, NULL)) { ++ ++(*l2_count); ++ } ++} ++ ++static void mali_delete_groups(void) ++{ ++ struct mali_group *group; ++ ++ group = mali_group_get_glob_group(0); ++ while (NULL != group) { ++ mali_group_delete(group); ++ group = mali_group_get_glob_group(0); ++ } ++ ++ MALI_DEBUG_ASSERT(0 == mali_group_get_glob_num_groups()); ++} ++ ++static void mali_delete_l2_cache_cores(void) ++{ ++ struct mali_l2_cache_core *l2; ++ ++ l2 = mali_l2_cache_core_get_glob_l2_core(0); ++ while (NULL != l2) { ++ mali_l2_cache_delete(l2); ++ l2 = mali_l2_cache_core_get_glob_l2_core(0); ++ } ++ ++ MALI_DEBUG_ASSERT(0 == mali_l2_cache_core_get_glob_num_l2_cores()); ++} ++ ++static struct mali_l2_cache_core *mali_create_l2_cache_core(_mali_osk_resource_t *resource) ++{ ++ struct mali_l2_cache_core *l2_cache = NULL; ++ ++ if (NULL != resource) { ++ ++ MALI_DEBUG_PRINT(3, ("Found L2 cache %s\n", resource->description)); ++ ++ l2_cache = mali_l2_cache_create(resource); ++ if (NULL == l2_cache) { ++ MALI_PRINT_ERROR(("Failed to create L2 cache object\n")); ++ return NULL; ++ } ++ } ++ MALI_DEBUG_PRINT(3, ("Created L2 cache core object\n")); ++ ++ return l2_cache; ++} ++ ++static _mali_osk_errcode_t mali_parse_config_l2_cache(void) ++{ ++ struct mali_l2_cache_core *l2_cache = NULL; ++ ++ if (mali_is_mali400()) { ++ _mali_osk_resource_t l2_resource; ++ if (_MALI_OSK_ERR_OK != _mali_osk_resource_find(global_gpu_base_address + 0x1000, &l2_resource)) { ++ MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache in config file\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ l2_cache = mali_create_l2_cache_core(&l2_resource); ++ if (NULL == l2_cache) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ mali_pm_domain_add_l2(mali_pmu_get_domain_mask(MALI_L20_DOMAIN_INDEX), l2_cache); ++ } else if (mali_is_mali450()) { ++ /* ++ * L2 for GP at 0x10000 ++ * L2 for PP0-3 at 0x01000 ++ * L2 for PP4-7 at 0x11000 (optional) ++ */ ++ ++ _mali_osk_resource_t l2_gp_resource; ++ _mali_osk_resource_t l2_pp_grp0_resource; ++ _mali_osk_resource_t l2_pp_grp1_resource; ++ ++ /* Make cluster for GP's L2 */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x10000, &l2_gp_resource)) { ++ MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for GP\n")); ++ l2_cache = mali_create_l2_cache_core(&l2_gp_resource); ++ if (NULL == l2_cache) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ mali_pm_domain_add_l2(mali_pmu_get_domain_mask(MALI_L20_DOMAIN_INDEX), l2_cache); ++ } else { ++ MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for GP in config file\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Find corresponding l2 domain */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x1000, &l2_pp_grp0_resource)) { ++ MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for PP group 0\n")); ++ l2_cache = mali_create_l2_cache_core(&l2_pp_grp0_resource); ++ if (NULL == l2_cache) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ mali_pm_domain_add_l2(mali_pmu_get_domain_mask(MALI_L21_DOMAIN_INDEX), l2_cache); ++ } else { ++ MALI_DEBUG_PRINT(3, ("Did not find required Mali L2 cache for PP group 0 in config file\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Second PP core group is optional, don't fail if we don't find it */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x11000, &l2_pp_grp1_resource)) { ++ MALI_DEBUG_PRINT(3, ("Creating Mali-450 L2 cache core for PP group 1\n")); ++ l2_cache = mali_create_l2_cache_core(&l2_pp_grp1_resource); ++ if (NULL == l2_cache) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ mali_pm_domain_add_l2(mali_pmu_get_domain_mask(MALI_L22_DOMAIN_INDEX), l2_cache); ++ } ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static struct mali_group *mali_create_group(struct mali_l2_cache_core *cache, ++ _mali_osk_resource_t *resource_mmu, ++ _mali_osk_resource_t *resource_gp, ++ _mali_osk_resource_t *resource_pp) ++{ ++ struct mali_mmu_core *mmu; ++ struct mali_group *group; ++ ++ MALI_DEBUG_PRINT(3, ("Starting new group for MMU %s\n", resource_mmu->description)); ++ ++ /* Create the group object */ ++ group = mali_group_create(cache, NULL, NULL); ++ if (NULL == group) { ++ MALI_PRINT_ERROR(("Failed to create group object for MMU %s\n", resource_mmu->description)); ++ return NULL; ++ } ++ ++ /* Create the MMU object inside group */ ++ mmu = mali_mmu_create(resource_mmu, group, MALI_FALSE); ++ if (NULL == mmu) { ++ MALI_PRINT_ERROR(("Failed to create MMU object\n")); ++ mali_group_delete(group); ++ return NULL; ++ } ++ ++ if (NULL != resource_gp) { ++ /* Create the GP core object inside this group */ ++ struct mali_gp_core *gp_core = mali_gp_create(resource_gp, group); ++ if (NULL == gp_core) { ++ /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ ++ MALI_PRINT_ERROR(("Failed to create GP object\n")); ++ mali_group_delete(group); ++ return NULL; ++ } ++ } ++ ++ if (NULL != resource_pp) { ++ struct mali_pp_core *pp_core; ++ ++ /* Create the PP core object inside this group */ ++ pp_core = mali_pp_create(resource_pp, group, MALI_FALSE, mali_get_bcast_id(resource_pp)); ++ if (NULL == pp_core) { ++ /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ ++ MALI_PRINT_ERROR(("Failed to create PP object\n")); ++ mali_group_delete(group); ++ return NULL; ++ } ++ } ++ ++ /* Reset group */ ++ mali_group_lock(group); ++ mali_group_reset(group); ++ mali_group_unlock(group); ++ ++ return group; ++} ++ ++static _mali_osk_errcode_t mali_create_virtual_group(_mali_osk_resource_t *resource_mmu_pp_bcast, ++ _mali_osk_resource_t *resource_pp_bcast, ++ _mali_osk_resource_t *resource_dlbu, ++ _mali_osk_resource_t *resource_bcast) ++{ ++ struct mali_mmu_core *mmu_pp_bcast_core; ++ struct mali_pp_core *pp_bcast_core; ++ struct mali_dlbu_core *dlbu_core; ++ struct mali_bcast_unit *bcast_core; ++ struct mali_group *group; ++ ++ MALI_DEBUG_PRINT(2, ("Starting new virtual group for MMU PP broadcast core %s\n", resource_mmu_pp_bcast->description)); ++ ++ /* Create the DLBU core object */ ++ dlbu_core = mali_dlbu_create(resource_dlbu); ++ if (NULL == dlbu_core) { ++ MALI_PRINT_ERROR(("Failed to create DLBU object \n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Create the Broadcast unit core */ ++ bcast_core = mali_bcast_unit_create(resource_bcast); ++ if (NULL == bcast_core) { ++ MALI_PRINT_ERROR(("Failed to create Broadcast unit object!\n")); ++ mali_dlbu_delete(dlbu_core); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Create the group object */ ++ group = mali_group_create(NULL, dlbu_core, bcast_core); ++ if (NULL == group) { ++ MALI_PRINT_ERROR(("Failed to create group object for MMU PP broadcast core %s\n", resource_mmu_pp_bcast->description)); ++ mali_bcast_unit_delete(bcast_core); ++ mali_dlbu_delete(dlbu_core); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Create the MMU object inside group */ ++ mmu_pp_bcast_core = mali_mmu_create(resource_mmu_pp_bcast, group, MALI_TRUE); ++ if (NULL == mmu_pp_bcast_core) { ++ MALI_PRINT_ERROR(("Failed to create MMU PP broadcast object\n")); ++ mali_group_delete(group); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Create the PP core object inside this group */ ++ pp_bcast_core = mali_pp_create(resource_pp_bcast, group, MALI_TRUE, 0); ++ if (NULL == pp_bcast_core) { ++ /* No need to clean up now, as we will clean up everything linked in from the cluster when we fail this function */ ++ MALI_PRINT_ERROR(("Failed to create PP object\n")); ++ mali_group_delete(group); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_parse_config_groups(void) ++{ ++ struct mali_group *group; ++ int cluster_id_gp = 0; ++ int cluster_id_pp_grp0 = 0; ++ int cluster_id_pp_grp1 = 0; ++ int i; ++ ++ _mali_osk_resource_t resource_gp; ++ _mali_osk_resource_t resource_gp_mmu; ++ _mali_osk_resource_t resource_pp[8]; ++ _mali_osk_resource_t resource_pp_mmu[8]; ++ _mali_osk_resource_t resource_pp_mmu_bcast; ++ _mali_osk_resource_t resource_pp_bcast; ++ _mali_osk_resource_t resource_dlbu; ++ _mali_osk_resource_t resource_bcast; ++ _mali_osk_errcode_t resource_gp_found; ++ _mali_osk_errcode_t resource_gp_mmu_found; ++ _mali_osk_errcode_t resource_pp_found[8]; ++ _mali_osk_errcode_t resource_pp_mmu_found[8]; ++ _mali_osk_errcode_t resource_pp_mmu_bcast_found; ++ _mali_osk_errcode_t resource_pp_bcast_found; ++ _mali_osk_errcode_t resource_dlbu_found; ++ _mali_osk_errcode_t resource_bcast_found; ++ ++ if (!(mali_is_mali400() || mali_is_mali450())) { ++ /* No known HW core */ ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ if (MALI_MAX_JOB_RUNTIME_DEFAULT == mali_max_job_runtime) { ++ /* Group settings are not overridden by module parameters, so use device settings */ ++ struct _mali_osk_device_data data = { 0, }; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { ++ /* Use device specific settings (if defined) */ ++ if (0 != data.max_job_runtime) { ++ mali_max_job_runtime = data.max_job_runtime; ++ } ++ } ++ } ++ ++ if (mali_is_mali450()) { ++ /* Mali-450 have separate L2s for GP, and PP core group(s) */ ++ cluster_id_pp_grp0 = 1; ++ cluster_id_pp_grp1 = 2; ++ } ++ ++ resource_gp_found = _mali_osk_resource_find(global_gpu_base_address + 0x00000, &resource_gp); ++ resource_gp_mmu_found = _mali_osk_resource_find(global_gpu_base_address + 0x03000, &resource_gp_mmu); ++ resource_pp_found[0] = _mali_osk_resource_find(global_gpu_base_address + 0x08000, &(resource_pp[0])); ++ resource_pp_found[1] = _mali_osk_resource_find(global_gpu_base_address + 0x0A000, &(resource_pp[1])); ++ resource_pp_found[2] = _mali_osk_resource_find(global_gpu_base_address + 0x0C000, &(resource_pp[2])); ++ resource_pp_found[3] = _mali_osk_resource_find(global_gpu_base_address + 0x0E000, &(resource_pp[3])); ++ resource_pp_found[4] = _mali_osk_resource_find(global_gpu_base_address + 0x28000, &(resource_pp[4])); ++ resource_pp_found[5] = _mali_osk_resource_find(global_gpu_base_address + 0x2A000, &(resource_pp[5])); ++ resource_pp_found[6] = _mali_osk_resource_find(global_gpu_base_address + 0x2C000, &(resource_pp[6])); ++ resource_pp_found[7] = _mali_osk_resource_find(global_gpu_base_address + 0x2E000, &(resource_pp[7])); ++ resource_pp_mmu_found[0] = _mali_osk_resource_find(global_gpu_base_address + 0x04000, &(resource_pp_mmu[0])); ++ resource_pp_mmu_found[1] = _mali_osk_resource_find(global_gpu_base_address + 0x05000, &(resource_pp_mmu[1])); ++ resource_pp_mmu_found[2] = _mali_osk_resource_find(global_gpu_base_address + 0x06000, &(resource_pp_mmu[2])); ++ resource_pp_mmu_found[3] = _mali_osk_resource_find(global_gpu_base_address + 0x07000, &(resource_pp_mmu[3])); ++ resource_pp_mmu_found[4] = _mali_osk_resource_find(global_gpu_base_address + 0x1C000, &(resource_pp_mmu[4])); ++ resource_pp_mmu_found[5] = _mali_osk_resource_find(global_gpu_base_address + 0x1D000, &(resource_pp_mmu[5])); ++ resource_pp_mmu_found[6] = _mali_osk_resource_find(global_gpu_base_address + 0x1E000, &(resource_pp_mmu[6])); ++ resource_pp_mmu_found[7] = _mali_osk_resource_find(global_gpu_base_address + 0x1F000, &(resource_pp_mmu[7])); ++ ++ ++ if (mali_is_mali450()) { ++ resource_bcast_found = _mali_osk_resource_find(global_gpu_base_address + 0x13000, &resource_bcast); ++ resource_dlbu_found = _mali_osk_resource_find(global_gpu_base_address + 0x14000, &resource_dlbu); ++ resource_pp_mmu_bcast_found = _mali_osk_resource_find(global_gpu_base_address + 0x15000, &resource_pp_mmu_bcast); ++ resource_pp_bcast_found = _mali_osk_resource_find(global_gpu_base_address + 0x16000, &resource_pp_bcast); ++ ++ if (_MALI_OSK_ERR_OK != resource_bcast_found || ++ _MALI_OSK_ERR_OK != resource_dlbu_found || ++ _MALI_OSK_ERR_OK != resource_pp_mmu_bcast_found || ++ _MALI_OSK_ERR_OK != resource_pp_bcast_found) { ++ /* Missing mandatory core(s) for Mali-450 */ ++ MALI_DEBUG_PRINT(2, ("Missing mandatory resources, Mali-450 needs DLBU, Broadcast unit, virtual PP core and virtual MMU\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ } ++ ++ if (_MALI_OSK_ERR_OK != resource_gp_found || ++ _MALI_OSK_ERR_OK != resource_gp_mmu_found || ++ _MALI_OSK_ERR_OK != resource_pp_found[0] || ++ _MALI_OSK_ERR_OK != resource_pp_mmu_found[0]) { ++ /* Missing mandatory core(s) */ ++ MALI_DEBUG_PRINT(2, ("Missing mandatory resource, need at least one GP and one PP, both with a separate MMU\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ MALI_DEBUG_ASSERT(1 <= mali_l2_cache_core_get_glob_num_l2_cores()); ++ group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_gp), &resource_gp_mmu, &resource_gp, NULL); ++ if (NULL == group) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Add GP in group, for PMU ref count */ ++ mali_pm_domain_add_group(mali_pmu_get_domain_mask(MALI_GP_DOMAIN_INDEX), group); ++ ++ /* Create group for first (and mandatory) PP core */ ++ MALI_DEBUG_ASSERT(mali_l2_cache_core_get_glob_num_l2_cores() >= (cluster_id_pp_grp0 + 1)); /* >= 1 on Mali-300 and Mali-400, >= 2 on Mali-450 */ ++ group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp0), &resource_pp_mmu[0], NULL, &resource_pp[0]); ++ if (NULL == group) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Find corresponding pp domain */ ++ mali_pm_domain_add_group(mali_pmu_get_domain_mask(MALI_PP0_DOMAIN_INDEX), group); ++ ++ mali_inited_pp_cores_group_1++; ++ ++ /* Create groups for rest of the cores in the first PP core group */ ++ for (i = 1; i < 4; i++) { /* First half of the PP cores belong to first core group */ ++ if (mali_inited_pp_cores_group_1 < mali_max_pp_cores_group_1) { ++ if (_MALI_OSK_ERR_OK == resource_pp_found[i] && _MALI_OSK_ERR_OK == resource_pp_mmu_found[i]) { ++ group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp0), &resource_pp_mmu[i], NULL, &resource_pp[i]); ++ if (NULL == group) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ mali_pm_domain_add_group(mali_pmu_get_domain_mask(i + MALI_PP0_DOMAIN_INDEX), group); ++ ++ mali_inited_pp_cores_group_1++; ++ } ++ } ++ } ++ ++ /* Create groups for cores in the second PP core group */ ++ for (i = 4; i < 8; i++) { /* Second half of the PP cores belong to second core group */ ++ if (mali_inited_pp_cores_group_2 < mali_max_pp_cores_group_2) { ++ if (_MALI_OSK_ERR_OK == resource_pp_found[i] && _MALI_OSK_ERR_OK == resource_pp_mmu_found[i]) { ++ MALI_DEBUG_ASSERT(mali_l2_cache_core_get_glob_num_l2_cores() >= 2); /* Only Mali-450 have a second core group */ ++ group = mali_create_group(mali_l2_cache_core_get_glob_l2_core(cluster_id_pp_grp1), &resource_pp_mmu[i], NULL, &resource_pp[i]); ++ if (NULL == group) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ mali_pm_domain_add_group(mali_pmu_get_domain_mask(i + MALI_PP0_DOMAIN_INDEX), group); ++ mali_inited_pp_cores_group_2++; ++ } ++ } ++ } ++ ++ if(mali_is_mali450()) { ++ _mali_osk_errcode_t err = mali_create_virtual_group(&resource_pp_mmu_bcast, &resource_pp_bcast, &resource_dlbu, &resource_bcast); ++ if (_MALI_OSK_ERR_OK != err) { ++ return err; ++ } ++ } ++ ++ mali_max_pp_cores_group_1 = mali_inited_pp_cores_group_1; ++ mali_max_pp_cores_group_2 = mali_inited_pp_cores_group_2; ++ MALI_DEBUG_PRINT(2, ("%d+%d PP cores initialized\n", mali_inited_pp_cores_group_1, mali_inited_pp_cores_group_2)); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_check_shared_interrupts(void) ++{ ++#if !defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ if (MALI_TRUE == _mali_osk_shared_interrupts()) { ++ MALI_PRINT_ERROR(("Shared interrupts detected, but driver support is not enabled\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++#endif /* !defined(CONFIG_MALI_SHARED_INTERRUPTS) */ ++ ++ /* It is OK to compile support for shared interrupts even if Mali is not using it. */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_create_pm_domains(void) ++{ ++ int i; ++ ++ for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) { ++ if (0x0 == mali_pmu_get_domain_mask(i)) continue; ++ ++ if (NULL == mali_pm_domain_create(mali_pmu_get_domain_mask(i))) { ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static void mali_use_default_pm_domain_config(void) ++{ ++ u32 pp_count_gr1 = 0; ++ u32 pp_count_gr2 = 0; ++ u32 l2_count = 0; ++ ++ MALI_DEBUG_ASSERT(0 != global_gpu_base_address); ++ ++ /* GP core */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x00000, NULL)) { ++ mali_pmu_set_domain_mask(MALI_GP_DOMAIN_INDEX, 0x01); ++ } ++ ++ /* PP0 - PP3 core */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x08000, NULL)) { ++ ++pp_count_gr1; ++ ++ if (mali_is_mali400()) { ++ mali_pmu_set_domain_mask(MALI_PP0_DOMAIN_INDEX, 0x01<<2); ++ } else if (mali_is_mali450()) { ++ mali_pmu_set_domain_mask(MALI_PP0_DOMAIN_INDEX, 0x01<<1); ++ } ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0A000, NULL)) { ++ ++pp_count_gr1; ++ ++ if (mali_is_mali400()) { ++ mali_pmu_set_domain_mask(MALI_PP1_DOMAIN_INDEX, 0x01<<3); ++ } else if (mali_is_mali450()) { ++ mali_pmu_set_domain_mask(MALI_PP1_DOMAIN_INDEX, 0x01<<2); ++ } ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0C000, NULL)) { ++ ++pp_count_gr1; ++ ++ if (mali_is_mali400()) { ++ mali_pmu_set_domain_mask(MALI_PP2_DOMAIN_INDEX, 0x01<<4); ++ } else if (mali_is_mali450()) { ++ mali_pmu_set_domain_mask(MALI_PP2_DOMAIN_INDEX, 0x01<<2); ++ } ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x0E000, NULL)) { ++ ++pp_count_gr1; ++ ++ if (mali_is_mali400()) { ++ mali_pmu_set_domain_mask(MALI_PP3_DOMAIN_INDEX, 0x01<<5); ++ } else if (mali_is_mali450()) { ++ mali_pmu_set_domain_mask(MALI_PP3_DOMAIN_INDEX, 0x01<<2); ++ } ++ } ++ ++ /* PP4 - PP7 */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x28000, NULL)) { ++ ++pp_count_gr2; ++ ++ mali_pmu_set_domain_mask(MALI_PP4_DOMAIN_INDEX, 0x01<<3); ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2A000, NULL)) { ++ ++pp_count_gr2; ++ ++ mali_pmu_set_domain_mask(MALI_PP5_DOMAIN_INDEX, 0x01<<3); ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2C000, NULL)) { ++ ++pp_count_gr2; ++ ++ mali_pmu_set_domain_mask(MALI_PP6_DOMAIN_INDEX, 0x01<<3); ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x2E000, NULL)) { ++ ++pp_count_gr2; ++ ++ mali_pmu_set_domain_mask(MALI_PP7_DOMAIN_INDEX, 0x01<<3); ++ } ++ ++ /* L2gp/L2PP0/L2PP4 */ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x10000, NULL)) { ++ ++l2_count; ++ ++ if (mali_is_mali400()) { ++ mali_pmu_set_domain_mask(MALI_L20_DOMAIN_INDEX, 0x01<<1); ++ } else if (mali_is_mali450()) { ++ mali_pmu_set_domain_mask(MALI_L20_DOMAIN_INDEX, 0x01<<0); ++ } ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x1000, NULL)) { ++ ++l2_count; ++ ++ mali_pmu_set_domain_mask(MALI_L21_DOMAIN_INDEX, 0x01<<1); ++ } ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x11000, NULL)) { ++ ++l2_count; ++ ++ mali_pmu_set_domain_mask(MALI_L22_DOMAIN_INDEX, 0x01<<3); ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Using default PMU domain config: (%d) gr1_pp_cores, (%d) gr2_pp_cores, (%d) l2_count. \n", pp_count_gr1, pp_count_gr2, l2_count)); ++} ++ ++static void mali_set_pmu_global_domain_config(void) ++{ ++ struct _mali_osk_device_data data = { 0, }; ++ int i = 0; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { ++ /* Check whether has customized pmu domain configure */ ++ for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) { ++ if (0 != data.pmu_domain_config[i]) break; ++ } ++ ++ if (MALI_MAX_NUMBER_OF_DOMAINS == i) { ++ mali_use_default_pm_domain_config(); ++ } else { ++ /* Copy the customer config to global config */ ++ mali_pmu_copy_domain_mask(data.pmu_domain_config, sizeof(data.pmu_domain_config)); ++ } ++ } ++} ++ ++static _mali_osk_errcode_t mali_parse_config_pmu(void) ++{ ++ _mali_osk_resource_t resource_pmu; ++ ++ MALI_DEBUG_ASSERT(0 != global_gpu_base_address); ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x02000, &resource_pmu)) { ++ struct mali_pmu_core *pmu; ++ ++ mali_set_pmu_global_domain_config(); ++ ++ pmu = mali_pmu_create(&resource_pmu); ++ if (NULL == pmu) { ++ MALI_PRINT_ERROR(("Failed to create PMU\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ } ++ ++ /* It's ok if the PMU doesn't exist */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_parse_config_dma(void) ++{ ++ _mali_osk_resource_t resource_dma; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_resource_find(global_gpu_base_address + 0x12000, &resource_dma)) { ++ if (NULL == mali_dma_create(&resource_dma)) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++ } else { ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++} ++ ++static _mali_osk_errcode_t mali_parse_config_memory(void) ++{ ++ _mali_osk_errcode_t ret; ++ ++ if (0 == mali_dedicated_mem_start && 0 == mali_dedicated_mem_size && 0 == mali_shared_mem_size) { ++ /* Memory settings are not overridden by module parameters, so use device settings */ ++ struct _mali_osk_device_data data = { 0, }; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { ++ /* Use device specific settings (if defined) */ ++ mali_dedicated_mem_start = data.dedicated_mem_start; ++ mali_dedicated_mem_size = data.dedicated_mem_size; ++ mali_shared_mem_size = data.shared_mem_size; ++ } ++ ++ if (0 == mali_dedicated_mem_start && 0 == mali_dedicated_mem_size && 0 == mali_shared_mem_size) { ++ /* No GPU memory specified */ ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Using device defined memory settings (dedicated: 0x%08X@0x%08X, shared: 0x%08X)\n", ++ mali_dedicated_mem_size, mali_dedicated_mem_start, mali_shared_mem_size)); ++ } else { ++ MALI_DEBUG_PRINT(2, ("Using module defined memory settings (dedicated: 0x%08X@0x%08X, shared: 0x%08X)\n", ++ mali_dedicated_mem_size, mali_dedicated_mem_start, mali_shared_mem_size)); ++ } ++ ++ if (0 < mali_dedicated_mem_size && 0 != mali_dedicated_mem_start) { ++ /* Dedicated memory */ ++ ret = mali_memory_core_resource_dedicated_memory(mali_dedicated_mem_start, mali_dedicated_mem_size); ++ if (_MALI_OSK_ERR_OK != ret) { ++ MALI_PRINT_ERROR(("Failed to register dedicated memory\n")); ++ mali_memory_terminate(); ++ return ret; ++ } ++ } ++ ++ if (0 < mali_shared_mem_size) { ++ /* Shared OS memory */ ++ ret = mali_memory_core_resource_os_memory(mali_shared_mem_size); ++ if (_MALI_OSK_ERR_OK != ret) { ++ MALI_PRINT_ERROR(("Failed to register shared OS memory\n")); ++ mali_memory_terminate(); ++ return ret; ++ } ++ } ++ ++ if (0 == mali_fb_start && 0 == mali_fb_size) { ++ /* Frame buffer settings are not overridden by module parameters, so use device settings */ ++ struct _mali_osk_device_data data = { 0, }; ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { ++ /* Use device specific settings (if defined) */ ++ mali_fb_start = data.fb_start; ++ mali_fb_size = data.fb_size; ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Using device defined frame buffer settings (0x%08X@0x%08X)\n", ++ mali_fb_size, mali_fb_start)); ++ } else { ++ MALI_DEBUG_PRINT(2, ("Using module defined frame buffer settings (0x%08X@0x%08X)\n", ++ mali_fb_size, mali_fb_start)); ++ } ++ ++ if (0 != mali_fb_size) { ++ /* Register frame buffer */ ++ ret = mali_mem_validation_add_range(mali_fb_start, mali_fb_size); ++ if (_MALI_OSK_ERR_OK != ret) { ++ MALI_PRINT_ERROR(("Failed to register frame buffer memory region\n")); ++ mali_memory_terminate(); ++ return ret; ++ } ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static void mali_detect_gpu_class(void) ++{ ++ u32 number_of_pp_cores = 0; ++ u32 number_of_l2_caches = 0; ++ ++ mali_resource_count(&number_of_pp_cores, &number_of_l2_caches); ++ if (number_of_l2_caches > 1) { ++ mali_gpu_class_is_mali450 = MALI_TRUE; ++ } ++} ++ ++_mali_osk_errcode_t mali_initialize_subsystems(void) ++{ ++ _mali_osk_errcode_t err; ++ struct mali_pmu_core *pmu; ++ ++ mali_pp_job_initialize(); ++ ++ err = mali_session_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto session_init_failed; ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ err = _mali_osk_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE); ++ if (_MALI_OSK_ERR_OK != err) { ++ /* No biggie if we weren't able to initialize the profiling */ ++ MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n")); ++ } ++#endif ++ ++ err = mali_memory_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto memory_init_failed; ++ ++ /* Configure memory early. Memory allocation needed for mali_mmu_initialize. */ ++ err = mali_parse_config_memory(); ++ if (_MALI_OSK_ERR_OK != err) goto parse_memory_config_failed; ++ ++ err = mali_set_global_gpu_base_address(); ++ if (_MALI_OSK_ERR_OK != err) goto set_global_gpu_base_address_failed; ++ ++ /* Detect gpu class according to l2 cache number */ ++ mali_detect_gpu_class(); ++ ++ err = mali_check_shared_interrupts(); ++ if (_MALI_OSK_ERR_OK != err) goto check_shared_interrupts_failed; ++ ++ err = mali_pp_scheduler_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto pp_scheduler_init_failed; ++ ++ /* Initialize the power management module */ ++ err = mali_pm_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto pm_init_failed; ++ ++ /* Initialize the MALI PMU */ ++ err = mali_parse_config_pmu(); ++ if (_MALI_OSK_ERR_OK != err) goto parse_pmu_config_failed; ++ ++ /* Make sure the power stays on for the rest of this function */ ++ err = _mali_osk_pm_dev_ref_add(); ++ if (_MALI_OSK_ERR_OK != err) goto pm_always_on_failed; ++ ++ /* ++ * If run-time PM is used, then the mali_pm module has now already been ++ * notified that the power now is on (through the resume callback functions). ++ * However, if run-time PM is not used, then there will probably not be any ++ * calls to the resume callback functions, so we need to explicitly tell it ++ * that the power is on. ++ */ ++ mali_pm_set_power_is_on(); ++ ++ /* Reset PMU HW and ensure all Mali power domains are on */ ++ pmu = mali_pmu_get_global_pmu_core(); ++ if (NULL != pmu) { ++ err = mali_pmu_reset(pmu); ++ if (_MALI_OSK_ERR_OK != err) goto pmu_reset_failed; ++ } ++ ++ /* Detect which Mali GPU we are dealing with */ ++ err = mali_parse_product_info(); ++ if (_MALI_OSK_ERR_OK != err) goto product_info_parsing_failed; ++ ++ /* The global_product_id is now populated with the correct Mali GPU */ ++ ++ /* Create PM domains only if PMU exists */ ++ if (NULL != pmu) { ++ err = mali_create_pm_domains(); ++ if (_MALI_OSK_ERR_OK != err) goto pm_domain_failed; ++ } ++ ++ /* Initialize MMU module */ ++ err = mali_mmu_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto mmu_init_failed; ++ ++ if (mali_is_mali450()) { ++ err = mali_dlbu_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto dlbu_init_failed; ++ ++ err = mali_parse_config_dma(); ++ if (_MALI_OSK_ERR_OK != err) goto dma_parsing_failed; ++ } ++ ++ /* Start configuring the actual Mali hardware. */ ++ err = mali_parse_config_l2_cache(); ++ if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; ++ err = mali_parse_config_groups(); ++ if (_MALI_OSK_ERR_OK != err) goto config_parsing_failed; ++ ++ /* Initialize the schedulers */ ++ err = mali_scheduler_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto scheduler_init_failed; ++ err = mali_gp_scheduler_initialize(); ++ if (_MALI_OSK_ERR_OK != err) goto gp_scheduler_init_failed; ++ ++ /* PP scheduler population can't fail */ ++ mali_pp_scheduler_populate(); ++ ++ /* Initialize the GPU utilization tracking */ ++ err = mali_utilization_init(); ++ if (_MALI_OSK_ERR_OK != err) goto utilization_init_failed; ++ ++ /* Allowing the system to be turned off */ ++ _mali_osk_pm_dev_ref_dec(); ++ ++ MALI_SUCCESS; /* all ok */ ++ ++ /* Error handling */ ++ ++utilization_init_failed: ++ mali_pp_scheduler_depopulate(); ++ mali_gp_scheduler_terminate(); ++gp_scheduler_init_failed: ++ mali_scheduler_terminate(); ++scheduler_init_failed: ++config_parsing_failed: ++ mali_delete_groups(); /* Delete any groups not (yet) owned by a scheduler */ ++ mali_delete_l2_cache_cores(); /* Delete L2 cache cores even if config parsing failed. */ ++ { ++ struct mali_dma_core *dma = mali_dma_get_global_dma_core(); ++ if (NULL != dma) mali_dma_delete(dma); ++ } ++dma_parsing_failed: ++ mali_dlbu_terminate(); ++dlbu_init_failed: ++ mali_mmu_terminate(); ++mmu_init_failed: ++ mali_pm_domain_terminate(); ++pm_domain_failed: ++ /* Nothing to roll back */ ++product_info_parsing_failed: ++ /* Nothing to roll back */ ++pmu_reset_failed: ++ /* Allowing the system to be turned off */ ++ _mali_osk_pm_dev_ref_dec(); ++pm_always_on_failed: ++ pmu = mali_pmu_get_global_pmu_core(); ++ if (NULL != pmu) { ++ mali_pmu_delete(pmu); ++ } ++parse_pmu_config_failed: ++ mali_pm_terminate(); ++pm_init_failed: ++ mali_pp_scheduler_terminate(); ++pp_scheduler_init_failed: ++check_shared_interrupts_failed: ++ global_gpu_base_address = 0; ++set_global_gpu_base_address_failed: ++ /* undoing mali_parse_config_memory() is done by mali_memory_terminate() */ ++parse_memory_config_failed: ++ mali_memory_terminate(); ++memory_init_failed: ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_term(); ++#endif ++ mali_session_terminate(); ++session_init_failed: ++ mali_pp_job_terminate(); ++ return err; ++} ++ ++void mali_terminate_subsystems(void) ++{ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ struct mali_dma_core *dma = mali_dma_get_global_dma_core(); ++ ++ MALI_DEBUG_PRINT(2, ("terminate_subsystems() called\n")); ++ ++ /* shut down subsystems in reverse order from startup */ ++ ++ /* We need the GPU to be powered up for the terminate sequence */ ++ _mali_osk_pm_dev_ref_add(); ++ ++ mali_utilization_term(); ++ mali_pp_scheduler_depopulate(); ++ mali_gp_scheduler_terminate(); ++ mali_scheduler_terminate(); ++ mali_delete_l2_cache_cores(); ++ if (mali_is_mali450()) { ++ mali_dlbu_terminate(); ++ } ++ mali_mmu_terminate(); ++ if (NULL != pmu) { ++ mali_pmu_delete(pmu); ++ } ++ if (NULL != dma) { ++ mali_dma_delete(dma); ++ } ++ mali_pm_terminate(); ++ mali_memory_terminate(); ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_term(); ++#endif ++ ++ /* Allowing the system to be turned off */ ++ _mali_osk_pm_dev_ref_dec(); ++ ++ mali_pp_scheduler_terminate(); ++ mali_session_terminate(); ++ ++ mali_pp_job_terminate(); ++} ++ ++_mali_product_id_t mali_kernel_core_get_product_id(void) ++{ ++ return global_product_id; ++} ++ ++u32 mali_kernel_core_get_gpu_major_version(void) ++{ ++ return global_gpu_major_version; ++} ++ ++u32 mali_kernel_core_get_gpu_minor_version(void) ++{ ++ return global_gpu_minor_version; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ /* check compatability */ ++ if ( args->version == _MALI_UK_API_VERSION ) { ++ args->compatible = 1; ++ } else { ++ args->compatible = 0; ++ } ++ ++ args->version = _MALI_UK_API_VERSION; /* report our version */ ++ ++ /* success regardless of being compatible or not */ ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args ) ++{ ++ _mali_osk_errcode_t err; ++ _mali_osk_notification_t * notification; ++ _mali_osk_notification_queue_t *queue; ++ ++ /* check input */ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ queue = ((struct mali_session_data *)args->ctx)->ioctl_queue; ++ ++ /* if the queue does not exist we're currently shutting down */ ++ if (NULL == queue) { ++ MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n")); ++ args->type = _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS; ++ MALI_SUCCESS; ++ } ++ ++ /* receive a notification, might sleep */ ++ err = _mali_osk_notification_queue_receive(queue, ¬ification); ++ if (_MALI_OSK_ERR_OK != err) { ++ MALI_ERROR(err); /* errcode returned, pass on to caller */ ++ } ++ ++ /* copy the buffer to the user */ ++ args->type = (_mali_uk_notification_type)notification->notification_type; ++ _mali_osk_memcpy(&args->data, notification->result_buffer, notification->result_buffer_size); ++ ++ /* finished with the notification */ ++ _mali_osk_notification_delete( notification ); ++ ++ MALI_SUCCESS; /* all ok */ ++} ++ ++_mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args ) ++{ ++ _mali_osk_notification_t * notification; ++ _mali_osk_notification_queue_t *queue; ++ ++ /* check input */ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ queue = ((struct mali_session_data *)args->ctx)->ioctl_queue; ++ ++ /* if the queue does not exist we're currently shutting down */ ++ if (NULL == queue) { ++ MALI_DEBUG_PRINT(1, ("No notification queue registered with the session. Asking userspace to stop querying\n")); ++ MALI_SUCCESS; ++ } ++ ++ notification = _mali_osk_notification_create(args->type, 0); ++ if (NULL == notification) { ++ MALI_PRINT_ERROR( ("Failed to create notification object\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ _mali_osk_notification_queue_send(queue, notification); ++ ++ MALI_SUCCESS; /* all ok */ ++} ++ ++_mali_osk_errcode_t _mali_ukk_request_high_priority( _mali_uk_request_high_priority_s *args ) ++{ ++ struct mali_session_data *session; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session = (struct mali_session_data *) args->ctx; ++ ++ if (!session->use_high_priority_job_queue) { ++ session->use_high_priority_job_queue = MALI_TRUE; ++ MALI_DEBUG_PRINT(2, ("Session 0x%08X with pid %d was granted higher priority.\n", session, _mali_osk_get_pid())); ++ } ++ ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_open(void **context) ++{ ++ u32 i; ++ struct mali_session_data *session; ++ ++ /* allocated struct to track this session */ ++ session = (struct mali_session_data *)_mali_osk_calloc(1, sizeof(struct mali_session_data)); ++ MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_NOMEM); ++ ++ MALI_DEBUG_PRINT(3, ("Session starting\n")); ++ ++ /* create a response queue for this session */ ++ session->ioctl_queue = _mali_osk_notification_queue_init(); ++ if (NULL == session->ioctl_queue) { ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ session->page_directory = mali_mmu_pagedir_alloc(); ++ if (NULL == session->page_directory) { ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_mmu_pagedir_map(session->page_directory, MALI_DLBU_VIRT_ADDR, _MALI_OSK_MALI_PAGE_SIZE)) { ++ MALI_PRINT_ERROR(("Failed to map DLBU page into session\n")); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ if (0 != mali_dlbu_phys_addr) { ++ mali_mmu_pagedir_update(session->page_directory, MALI_DLBU_VIRT_ADDR, mali_dlbu_phys_addr, ++ _MALI_OSK_MALI_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT); ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_memory_session_begin(session)) { ++ mali_mmu_pagedir_free(session->page_directory); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ /* Create soft system. */ ++ session->soft_job_system = mali_soft_job_system_create(session); ++ if (NULL == session->soft_job_system) { ++ mali_memory_session_end(session); ++ mali_mmu_pagedir_free(session->page_directory); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ /* Create timeline system. */ ++ session->timeline_system = mali_timeline_system_create(session); ++ if (NULL == session->timeline_system) { ++ mali_soft_job_system_destroy(session->soft_job_system); ++ mali_memory_session_end(session); ++ mali_mmu_pagedir_free(session->page_directory); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ if ( _MALI_OSK_ERR_OK != _mali_osk_atomic_init(&session->number_of_window_jobs, 0)) { ++ MALI_DEBUG_PRINT_ERROR(("Initialization of atomic number_of_window_jobs failed.\n")); ++ mali_timeline_system_destroy(session->timeline_system); ++ mali_soft_job_system_destroy(session->soft_job_system); ++ mali_memory_session_end(session); ++ mali_mmu_pagedir_free(session->page_directory); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ return _MALI_OSK_ERR_FAULT; ++ } ++#endif ++ ++ session->use_high_priority_job_queue = MALI_FALSE; ++ ++ /* Initialize list of PP jobs on this session. */ ++ _MALI_OSK_INIT_LIST_HEAD(&session->pp_job_list); ++ ++ /* Initialize the pp_job_fb_lookup_list array used to quickly lookup jobs from a given frame builder */ ++ for (i = 0; i < MALI_PP_JOB_FB_LOOKUP_LIST_SIZE; ++i) { ++ _MALI_OSK_INIT_LIST_HEAD(&session->pp_job_fb_lookup_list[i]); ++ } ++ ++ *context = (void*)session; ++ ++ /* Add session to the list of all sessions. */ ++ mali_session_add(session); ++ ++ MALI_DEBUG_PRINT(2, ("Session started\n")); ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_close(void **context) ++{ ++ struct mali_session_data *session; ++ MALI_CHECK_NON_NULL(context, _MALI_OSK_ERR_INVALID_ARGS); ++ session = (struct mali_session_data *)*context; ++ ++ MALI_DEBUG_PRINT(3, ("Session ending\n")); ++ ++ MALI_DEBUG_ASSERT_POINTER(session->soft_job_system); ++ MALI_DEBUG_ASSERT_POINTER(session->timeline_system); ++ ++ /* Remove session from list of all sessions. */ ++ mali_session_remove(session); ++ ++ /* This flag is used to prevent queueing of jobs due to activation. */ ++ session->is_aborting = MALI_TRUE; ++ ++ /* Stop the soft job timer. */ ++ mali_timeline_system_stop_timer(session->timeline_system); ++ ++ /* Abort queued and running GP and PP jobs. */ ++ mali_gp_scheduler_abort_session(session); ++ mali_pp_scheduler_abort_session(session); ++ ++ /* Abort the soft job system. */ ++ mali_soft_job_system_abort(session->soft_job_system); ++ ++ /* Force execution of all pending bottom half processing for GP and PP. */ ++ _mali_osk_wq_flush(); ++ ++ /* The session PP list should now be empty. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&session->pp_job_list)); ++ ++ /* At this point the GP and PP scheduler no longer has any jobs queued or running from this ++ * session, and all soft jobs in the soft job system has been destroyed. */ ++ ++ /* Any trackers left in the timeline system are directly or indirectly waiting on external ++ * sync fences. Cancel all sync fence waiters to trigger activation of all remaining ++ * trackers. This call will sleep until all timelines are empty. */ ++ mali_timeline_system_abort(session->timeline_system); ++ ++ /* Flush pending work. ++ * Needed to make sure all bottom half processing related to this ++ * session has been completed, before we free internal data structures. ++ */ ++ _mali_osk_wq_flush(); ++ ++ /* Destroy timeline system. */ ++ mali_timeline_system_destroy(session->timeline_system); ++ session->timeline_system = NULL; ++ ++ /* Destroy soft system. */ ++ mali_soft_job_system_destroy(session->soft_job_system); ++ session->soft_job_system = NULL; ++ ++ MALI_DEBUG_CODE( { ++ /* Check that the pp_job_fb_lookup_list array is empty. */ ++ u32 i; ++ for (i = 0; i < MALI_PP_JOB_FB_LOOKUP_LIST_SIZE; ++i) ++ { ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&session->pp_job_fb_lookup_list[i])); ++ } ++ }); ++ ++ /* Free remaining memory allocated to this session */ ++ mali_memory_session_end(session); ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ _mali_osk_atomic_term(&session->number_of_window_jobs); ++#endif ++ ++ /* Free session data structures */ ++ mali_mmu_pagedir_free(session->page_directory); ++ _mali_osk_notification_queue_term(session->ioctl_queue); ++ _mali_osk_free(session); ++ ++ *context = NULL; ++ ++ MALI_DEBUG_PRINT(2, ("Session has ended\n")); ++ ++ MALI_SUCCESS; ++} ++ ++#if MALI_STATE_TRACKING ++u32 _mali_kernel_core_dump_state(char* buf, u32 size) ++{ ++ int n = 0; /* Number of bytes written to buf */ ++ ++ n += mali_gp_scheduler_dump_state(buf + n, size - n); ++ n += mali_pp_scheduler_dump_state(buf + n, size - n); ++ ++ return n; ++} ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.h +new file mode 100644 +index 0000000..0bbdb61 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_core.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_CORE_H__ ++#define __MALI_KERNEL_CORE_H__ ++ ++#include "mali_osk.h" ++ ++typedef enum { ++ _MALI_PRODUCT_ID_UNKNOWN, ++ _MALI_PRODUCT_ID_MALI200, ++ _MALI_PRODUCT_ID_MALI300, ++ _MALI_PRODUCT_ID_MALI400, ++ _MALI_PRODUCT_ID_MALI450, ++} _mali_product_id_t; ++ ++extern mali_bool mali_gpu_class_is_mali450; ++ ++_mali_osk_errcode_t mali_initialize_subsystems(void); ++ ++void mali_terminate_subsystems(void); ++ ++_mali_product_id_t mali_kernel_core_get_product_id(void); ++ ++u32 mali_kernel_core_get_gpu_major_version(void); ++ ++u32 mali_kernel_core_get_gpu_minor_version(void); ++ ++u32 _mali_kernel_core_dump_state(char* buf, u32 size); ++ ++MALI_STATIC_INLINE mali_bool mali_is_mali450(void) ++{ ++#if defined(CONFIG_MALI450) ++ return mali_gpu_class_is_mali450; ++#else ++ return MALI_FALSE; ++#endif ++} ++ ++MALI_STATIC_INLINE mali_bool mali_is_mali400(void) ++{ ++#if !defined(CONFIG_MALI450) ++ return MALI_TRUE; ++#else ++ return !mali_gpu_class_is_mali450; ++#endif ++} ++ ++#endif /* __MALI_KERNEL_CORE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.c +new file mode 100644 +index 0000000..67b47b8 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.c +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_kernel_descriptor_mapping.h" ++#include "mali_osk.h" ++#include "mali_osk_bitops.h" ++ ++#define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1)) ++ ++/** ++ * Allocate a descriptor table capable of holding 'count' mappings ++ * @param count Number of mappings in the table ++ * @return Pointer to a new table, NULL on error ++ */ ++static mali_descriptor_table * descriptor_table_alloc(int count); ++ ++/** ++ * Free a descriptor table ++ * @param table The table to free ++ */ ++static void descriptor_table_free(mali_descriptor_table * table); ++ ++mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int max_entries) ++{ ++ mali_descriptor_mapping * map = _mali_osk_calloc(1, sizeof(mali_descriptor_mapping)); ++ ++ init_entries = MALI_PAD_INT(init_entries); ++ max_entries = MALI_PAD_INT(max_entries); ++ ++ if (NULL != map) { ++ map->table = descriptor_table_alloc(init_entries); ++ if (NULL != map->table) { ++ map->lock = _mali_osk_mutex_rw_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP); ++ if (NULL != map->lock) { ++ _mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */ ++ map->max_nr_mappings_allowed = max_entries; ++ map->current_nr_mappings = init_entries; ++ return map; ++ } ++ descriptor_table_free(map->table); ++ } ++ _mali_osk_free(map); ++ } ++ return NULL; ++} ++ ++void mali_descriptor_mapping_destroy(mali_descriptor_mapping * map) ++{ ++ descriptor_table_free(map->table); ++ _mali_osk_mutex_rw_term(map->lock); ++ _mali_osk_free(map); ++} ++ ++_mali_osk_errcode_t mali_descriptor_mapping_allocate_mapping(mali_descriptor_mapping * map, void * target, int *odescriptor) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ int new_descriptor; ++ ++ MALI_DEBUG_ASSERT_POINTER(map); ++ MALI_DEBUG_ASSERT_POINTER(odescriptor); ++ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW); ++ new_descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings); ++ if (new_descriptor == map->current_nr_mappings) { ++ /* no free descriptor, try to expand the table */ ++ mali_descriptor_table * new_table, * old_table; ++ if (map->current_nr_mappings >= map->max_nr_mappings_allowed) goto unlock_and_exit; ++ ++ map->current_nr_mappings += BITS_PER_LONG; ++ new_table = descriptor_table_alloc(map->current_nr_mappings); ++ if (NULL == new_table) goto unlock_and_exit; ++ ++ old_table = map->table; ++ _mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG); ++ _mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*)); ++ map->table = new_table; ++ descriptor_table_free(old_table); ++ } ++ ++ /* we have found a valid descriptor, set the value and usage bit */ ++ _mali_osk_set_nonatomic_bit(new_descriptor, map->table->usage); ++ map->table->mappings[new_descriptor] = target; ++ *odescriptor = new_descriptor; ++ err = _MALI_OSK_ERR_OK; ++ ++unlock_and_exit: ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW); ++ MALI_ERROR(err); ++} ++ ++void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void (*callback)(int, void*)) ++{ ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(map); ++ MALI_DEBUG_ASSERT_POINTER(callback); ++ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO); ++ /* id 0 is skipped as it's an reserved ID not mapping to anything */ ++ for (i = 1; i < map->current_nr_mappings; ++i) { ++ if (_mali_osk_test_bit(i, map->table->usage)) { ++ callback(i, map->table->mappings[i]); ++ } ++ } ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO); ++} ++ ++_mali_osk_errcode_t mali_descriptor_mapping_get(mali_descriptor_mapping * map, int descriptor, void** target) ++{ ++ _mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT; ++ MALI_DEBUG_ASSERT_POINTER(map); ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO); ++ if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { ++ *target = map->table->mappings[descriptor]; ++ result = _MALI_OSK_ERR_OK; ++ } else *target = NULL; ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO); ++ MALI_ERROR(result); ++} ++ ++_mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, int descriptor, void * target) ++{ ++ _mali_osk_errcode_t result = _MALI_OSK_ERR_FAULT; ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO); ++ if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { ++ map->table->mappings[descriptor] = target; ++ result = _MALI_OSK_ERR_OK; ++ } ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO); ++ MALI_ERROR(result); ++} ++ ++void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor) ++{ ++ void *old_value = NULL; ++ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW); ++ if ( (descriptor >= 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage) ) { ++ old_value = map->table->mappings[descriptor]; ++ map->table->mappings[descriptor] = NULL; ++ _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage); ++ } ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW); ++ ++ return old_value; ++} ++ ++static mali_descriptor_table * descriptor_table_alloc(int count) ++{ ++ mali_descriptor_table * table; ++ ++ table = _mali_osk_calloc(1, sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count)); ++ ++ if (NULL != table) { ++ table->usage = (u32*)((u8*)table + sizeof(mali_descriptor_table)); ++ table->mappings = (void**)((u8*)table + sizeof(mali_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG)); ++ } ++ ++ return table; ++} ++ ++static void descriptor_table_free(mali_descriptor_table * table) ++{ ++ _mali_osk_free(table); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.h +new file mode 100644 +index 0000000..c7017e1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_descriptor_mapping.h +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_kernel_descriptor_mapping.h ++ */ ++ ++#ifndef __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ ++#define __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ ++ ++#include "mali_osk.h" ++ ++/** ++ * The actual descriptor mapping table, never directly accessed by clients ++ */ ++typedef struct mali_descriptor_table { ++ u32 * usage; /**< Pointer to bitpattern indicating if a descriptor is valid/used or not */ ++ void** mappings; /**< Array of the pointers the descriptors map to */ ++} mali_descriptor_table; ++ ++/** ++ * The descriptor mapping object ++ * Provides a separate namespace where we can map an integer to a pointer ++ */ ++typedef struct mali_descriptor_mapping { ++ _mali_osk_mutex_rw_t *lock; /**< Lock protecting access to the mapping object */ ++ int max_nr_mappings_allowed; /**< Max number of mappings to support in this namespace */ ++ int current_nr_mappings; /**< Current number of possible mappings */ ++ mali_descriptor_table * table; /**< Pointer to the current mapping table */ ++} mali_descriptor_mapping; ++ ++/** ++ * Create a descriptor mapping object ++ * Create a descriptor mapping capable of holding init_entries growable to max_entries ++ * @param init_entries Number of entries to preallocate memory for ++ * @param max_entries Number of entries to max support ++ * @return Pointer to a descriptor mapping object, NULL on failure ++ */ ++mali_descriptor_mapping * mali_descriptor_mapping_create(int init_entries, int max_entries); ++ ++/** ++ * Destroy a descriptor mapping object ++ * @param map The map to free ++ */ ++void mali_descriptor_mapping_destroy(mali_descriptor_mapping * map); ++ ++/** ++ * Allocate a new mapping entry (descriptor ID) ++ * Allocates a new entry in the map. ++ * @param map The map to allocate a new entry in ++ * @param target The value to map to ++ * @return The descriptor allocated, a negative value on error ++ */ ++_mali_osk_errcode_t mali_descriptor_mapping_allocate_mapping(mali_descriptor_mapping * map, void * target, int *descriptor); ++ ++/** ++ * Get the value mapped to by a descriptor ID ++ * @param map The map to lookup the descriptor id in ++ * @param descriptor The descriptor ID to lookup ++ * @param target Pointer to a pointer which will receive the stored value ++ * @return 0 on successful lookup, negative on error ++ */ ++_mali_osk_errcode_t mali_descriptor_mapping_get(mali_descriptor_mapping * map, int descriptor, void** target); ++ ++/** ++ * Set the value mapped to by a descriptor ID ++ * @param map The map to lookup the descriptor id in ++ * @param descriptor The descriptor ID to lookup ++ * @param target Pointer to replace the current value with ++ * @return 0 on successful lookup, negative on error ++ */ ++_mali_osk_errcode_t mali_descriptor_mapping_set(mali_descriptor_mapping * map, int descriptor, void * target); ++ ++/** ++ * Call the specified callback function for each descriptor in map. ++ * Entire function is mutex protected. ++ * @param map The map to do callbacks for ++ * @param callback A callback function which will be calle for each entry in map ++ */ ++void mali_descriptor_mapping_call_for_each(mali_descriptor_mapping * map, void (*callback)(int, void*)); ++ ++/** ++ * Free the descriptor ID ++ * For the descriptor to be reused it has to be freed ++ * @param map The map to free the descriptor from ++ * @param descriptor The descriptor ID to free ++ * ++ * @return old value of descriptor mapping ++ */ ++void *mali_descriptor_mapping_free(mali_descriptor_mapping * map, int descriptor); ++ ++#endif /* __MALI_KERNEL_DESCRIPTOR_MAPPING_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.c +new file mode 100644 +index 0000000..596015a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.c +@@ -0,0 +1,439 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_utilization.h" ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_scheduler.h" ++ ++/* Thresholds for GP bound detection. */ ++#define MALI_GP_BOUND_GP_UTILIZATION_THRESHOLD 240 ++#define MALI_GP_BOUND_PP_UTILIZATION_THRESHOLD 250 ++ ++/* Define how often to calculate and report GPU utilization, in milliseconds */ ++static _mali_osk_spinlock_irq_t *time_data_lock; ++ ++static u32 num_running_gp_cores; ++static u32 num_running_pp_cores; ++ ++static u64 work_start_time_gpu = 0; ++static u64 work_start_time_gp = 0; ++static u64 work_start_time_pp = 0; ++static u64 accumulated_work_time_gpu = 0; ++static u64 accumulated_work_time_gp = 0; ++static u64 accumulated_work_time_pp = 0; ++ ++static u64 period_start_time = 0; ++static _mali_osk_timer_t *utilization_timer = NULL; ++static mali_bool timer_running = MALI_FALSE; ++ ++static u32 last_utilization_gpu = 0 ; ++static u32 last_utilization_gp = 0 ; ++static u32 last_utilization_pp = 0 ; ++ ++static u32 mali_utilization_timeout = 1000; ++void (*mali_utilization_callback)(struct mali_gpu_utilization_data *data) = NULL; ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++extern void mali_power_performance_policy_callback(struct mali_gpu_utilization_data *data); ++#define NUMBER_OF_NANOSECONDS_PER_SECOND 1000000000ULL ++ ++static u32 calculate_window_render_fps(u64 time_period) ++{ ++ u32 max_window_number; ++ u64 tmp; ++ u64 max = time_period; ++ u32 leading_zeroes; ++ u32 shift_val; ++ u32 time_period_shift; ++ u32 max_window_number_shift; ++ u32 ret_val; ++ ++ max_window_number = mali_session_max_window_num(); ++ /* To avoid float division, extend the dividend to ns unit */ ++ tmp = (u64)max_window_number * NUMBER_OF_NANOSECONDS_PER_SECOND; ++ if (tmp > time_period) { ++ max = tmp; ++ } ++ ++ /* ++ * We may have 64-bit values, a dividend or a divisor or both ++ * To avoid dependencies to a 64-bit divider, we shift down the two values ++ * equally first. ++ */ ++ leading_zeroes = _mali_osk_clz((u32)(max >> 32)); ++ shift_val = 32 - leading_zeroes; ++ ++ time_period_shift = (u32)(time_period >> shift_val); ++ max_window_number_shift = (u32)(tmp >> shift_val); ++ ++ ret_val = max_window_number_shift / time_period_shift; ++ ++ return ret_val; ++} ++#endif /* defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) */ ++ ++static void calculate_gpu_utilization(void* arg) ++{ ++ u64 time_now; ++ u64 time_period; ++ u32 leading_zeroes; ++ u32 shift_val; ++ u32 work_normalized_gpu; ++ u32 work_normalized_gp; ++ u32 work_normalized_pp; ++ u32 period_normalized; ++ u32 utilization_gpu; ++ u32 utilization_gp; ++ u32 utilization_pp; ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ u32 window_render_fps; ++#endif ++ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ if (accumulated_work_time_gpu == 0 && work_start_time_gpu == 0) { ++ /* ++ * No work done for this period ++ * - No need to reschedule timer ++ * - Report zero usage ++ */ ++ timer_running = MALI_FALSE; ++ ++ last_utilization_gpu = 0; ++ last_utilization_gp = 0; ++ last_utilization_pp = 0; ++ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ ++ if (NULL != mali_utilization_callback) { ++ struct mali_gpu_utilization_data data = { 0, }; ++ mali_utilization_callback(&data); ++ } ++ ++ mali_scheduler_hint_disable(MALI_SCHEDULER_HINT_GP_BOUND); ++ ++ return; ++ } ++ ++ time_now = _mali_osk_time_get_ns(); ++ ++ time_period = time_now - period_start_time; ++ ++ /* If we are currently busy, update working period up to now */ ++ if (work_start_time_gpu != 0) { ++ accumulated_work_time_gpu += (time_now - work_start_time_gpu); ++ work_start_time_gpu = time_now; ++ ++ /* GP and/or PP will also be busy if the GPU is busy at this point */ ++ ++ if (work_start_time_gp != 0) { ++ accumulated_work_time_gp += (time_now - work_start_time_gp); ++ work_start_time_gp = time_now; ++ } ++ ++ if (work_start_time_pp != 0) { ++ accumulated_work_time_pp += (time_now - work_start_time_pp); ++ work_start_time_pp = time_now; ++ } ++ } ++ ++ /* ++ * We have two 64-bit values, a dividend and a divisor. ++ * To avoid dependencies to a 64-bit divider, we shift down the two values ++ * equally first. ++ * We shift the dividend up and possibly the divisor down, making the result X in 256. ++ */ ++ ++ /* Shift the 64-bit values down so they fit inside a 32-bit integer */ ++ leading_zeroes = _mali_osk_clz((u32)(time_period >> 32)); ++ shift_val = 32 - leading_zeroes; ++ work_normalized_gpu = (u32)(accumulated_work_time_gpu >> shift_val); ++ work_normalized_gp = (u32)(accumulated_work_time_gp >> shift_val); ++ work_normalized_pp = (u32)(accumulated_work_time_pp >> shift_val); ++ period_normalized = (u32)(time_period >> shift_val); ++ ++ /* ++ * Now, we should report the usage in parts of 256 ++ * this means we must shift up the dividend or down the divisor by 8 ++ * (we could do a combination, but we just use one for simplicity, ++ * but the end result should be good enough anyway) ++ */ ++ if (period_normalized > 0x00FFFFFF) { ++ /* The divisor is so big that it is safe to shift it down */ ++ period_normalized >>= 8; ++ } else { ++ /* ++ * The divisor is so small that we can shift up the dividend, without loosing any data. ++ * (dividend is always smaller than the divisor) ++ */ ++ work_normalized_gpu <<= 8; ++ work_normalized_gp <<= 8; ++ work_normalized_pp <<= 8; ++ } ++ ++ utilization_gpu = work_normalized_gpu / period_normalized; ++ utilization_gp = work_normalized_gp / period_normalized; ++ utilization_pp = work_normalized_pp / period_normalized; ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ window_render_fps = calculate_window_render_fps(time_period); ++#endif ++ ++ last_utilization_gpu = utilization_gpu; ++ last_utilization_gp = utilization_gp; ++ last_utilization_pp = utilization_pp; ++ ++ if ((MALI_GP_BOUND_GP_UTILIZATION_THRESHOLD < last_utilization_gp) && ++ (MALI_GP_BOUND_PP_UTILIZATION_THRESHOLD > last_utilization_pp)) { ++ mali_scheduler_hint_enable(MALI_SCHEDULER_HINT_GP_BOUND); ++ } else { ++ mali_scheduler_hint_disable(MALI_SCHEDULER_HINT_GP_BOUND); ++ } ++ ++ /* starting a new period */ ++ accumulated_work_time_gpu = 0; ++ accumulated_work_time_gp = 0; ++ accumulated_work_time_pp = 0; ++ period_start_time = time_now; ++ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ ++ _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(mali_utilization_timeout)); ++ ++ if (NULL != mali_utilization_callback) { ++ struct mali_gpu_utilization_data data = { ++ utilization_gpu, utilization_gp, utilization_pp, ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ window_render_fps, window_render_fps ++#endif ++ }; ++ mali_utilization_callback(&data); ++ } ++} ++ ++_mali_osk_errcode_t mali_utilization_init(void) ++{ ++#if USING_GPU_UTILIZATION ++ struct _mali_osk_device_data data; ++ if (_MALI_OSK_ERR_OK == _mali_osk_device_data_get(&data)) { ++ /* Use device specific settings (if defined) */ ++ if (0 != data.utilization_interval) { ++ mali_utilization_timeout = data.utilization_interval; ++ } ++ if (NULL != data.utilization_callback) { ++ mali_utilization_callback = data.utilization_callback; ++ MALI_DEBUG_PRINT(2, ("Mali GPU Utilization: Platform has it's own policy \n")); ++ MALI_DEBUG_PRINT(2, ("Mali GPU Utilization: Utilization handler installed with interval %u\n", mali_utilization_timeout)); ++ } ++ } ++#endif ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ if (mali_utilization_callback == NULL) { ++ MALI_DEBUG_PRINT(2, ("Mali GPU Utilization: MALI Power Performance Policy Algorithm \n")); ++ mali_utilization_callback = mali_power_performance_policy_callback; ++ } ++#endif ++ ++ if (NULL == mali_utilization_callback) { ++ MALI_DEBUG_PRINT(2, ("Mali GPU Utilization: No utilization handler installed\n")); ++ } ++ ++ time_data_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_UTILIZATION); ++ ++ if (NULL == time_data_lock) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ num_running_gp_cores = 0; ++ num_running_pp_cores = 0; ++ ++ utilization_timer = _mali_osk_timer_init(); ++ if (NULL == utilization_timer) { ++ _mali_osk_spinlock_irq_term(time_data_lock); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ _mali_osk_timer_setcallback(utilization_timer, calculate_gpu_utilization, NULL); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_utilization_suspend(void) ++{ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ if (timer_running == MALI_TRUE) { ++ timer_running = MALI_FALSE; ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ _mali_osk_timer_del(utilization_timer); ++ return; ++ } ++ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++} ++ ++void mali_utilization_term(void) ++{ ++ if (NULL != utilization_timer) { ++ _mali_osk_timer_del(utilization_timer); ++ timer_running = MALI_FALSE; ++ _mali_osk_timer_term(utilization_timer); ++ utilization_timer = NULL; ++ } ++ ++ _mali_osk_spinlock_irq_term(time_data_lock); ++} ++ ++void mali_utilization_gp_start(void) ++{ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ ++num_running_gp_cores; ++ if (1 == num_running_gp_cores) { ++ u64 time_now = _mali_osk_time_get_ns(); ++ ++ /* First GP core started, consider GP busy from now and onwards */ ++ work_start_time_gp = time_now; ++ ++ if (0 == num_running_pp_cores) { ++ /* ++ * There are no PP cores running, so this is also the point ++ * at which we consider the GPU to be busy as well. ++ */ ++ work_start_time_gpu = time_now; ++ } ++ ++ /* Start a new period (and timer) if needed */ ++ if (timer_running != MALI_TRUE) { ++ timer_running = MALI_TRUE; ++ period_start_time = time_now; ++ ++ /* Clear session->number_of_window_jobs */ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ mali_session_max_window_num(); ++#endif ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ ++ _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(mali_utilization_timeout)); ++ } else { ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ } ++ } else { ++ /* Nothing to do */ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ } ++} ++ ++void mali_utilization_pp_start(void) ++{ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ ++num_running_pp_cores; ++ if (1 == num_running_pp_cores) { ++ u64 time_now = _mali_osk_time_get_ns(); ++ ++ /* First PP core started, consider PP busy from now and onwards */ ++ work_start_time_pp = time_now; ++ ++ if (0 == num_running_gp_cores) { ++ /* ++ * There are no GP cores running, so this is also the point ++ * at which we consider the GPU to be busy as well. ++ */ ++ work_start_time_gpu = time_now; ++ } ++ ++ /* Start a new period (and timer) if needed */ ++ if (timer_running != MALI_TRUE) { ++ timer_running = MALI_TRUE; ++ period_start_time = time_now; ++ ++ /* Clear session->number_of_window_jobs */ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ mali_session_max_window_num(); ++#endif ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ ++ _mali_osk_timer_add(utilization_timer, _mali_osk_time_mstoticks(mali_utilization_timeout)); ++ } else { ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ } ++ } else { ++ /* Nothing to do */ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++ } ++} ++ ++void mali_utilization_gp_end(void) ++{ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ --num_running_gp_cores; ++ if (0 == num_running_gp_cores) { ++ u64 time_now = _mali_osk_time_get_ns(); ++ ++ /* Last GP core ended, consider GP idle from now and onwards */ ++ accumulated_work_time_gp += (time_now - work_start_time_gp); ++ work_start_time_gp = 0; ++ ++ if (0 == num_running_pp_cores) { ++ /* ++ * There are no PP cores running, so this is also the point ++ * at which we consider the GPU to be idle as well. ++ */ ++ accumulated_work_time_gpu += (time_now - work_start_time_gpu); ++ work_start_time_gpu = 0; ++ } ++ } ++ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++} ++ ++void mali_utilization_pp_end(void) ++{ ++ _mali_osk_spinlock_irq_lock(time_data_lock); ++ ++ --num_running_pp_cores; ++ if (0 == num_running_pp_cores) { ++ u64 time_now = _mali_osk_time_get_ns(); ++ ++ /* Last PP core ended, consider PP idle from now and onwards */ ++ accumulated_work_time_pp += (time_now - work_start_time_pp); ++ work_start_time_pp = 0; ++ ++ if (0 == num_running_gp_cores) { ++ /* ++ * There are no GP cores running, so this is also the point ++ * at which we consider the GPU to be idle as well. ++ */ ++ accumulated_work_time_gpu += (time_now - work_start_time_gpu); ++ work_start_time_gpu = 0; ++ } ++ } ++ ++ _mali_osk_spinlock_irq_unlock(time_data_lock); ++} ++ ++u32 _mali_ukk_utilization_gp_pp(void) ++{ ++ return last_utilization_gpu; ++} ++ ++u32 _mali_ukk_utilization_gp(void) ++{ ++ return last_utilization_gp; ++} ++ ++u32 _mali_ukk_utilization_pp(void) ++{ ++ return last_utilization_pp; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.h +new file mode 100644 +index 0000000..3aa3148 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_utilization.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_UTILIZATION_H__ ++#define __MALI_KERNEL_UTILIZATION_H__ ++ ++#include ++#include "mali_osk.h" ++ ++extern void (*mali_utilization_callback)(struct mali_gpu_utilization_data *data); ++ ++/** ++ * Initialize/start the Mali GPU utilization metrics reporting. ++ * ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t mali_utilization_init(void); ++ ++/** ++ * Terminate the Mali GPU utilization metrics reporting ++ */ ++void mali_utilization_term(void); ++ ++/** ++ * Check if Mali utilization is enabled ++ */ ++MALI_STATIC_INLINE mali_bool mali_utilization_enabled(void) ++{ ++ return (NULL != mali_utilization_callback); ++} ++ ++/** ++ * Should be called when a job is about to execute a GP job ++ */ ++void mali_utilization_gp_start(void); ++ ++/** ++ * Should be called when a job has completed executing a GP job ++ */ ++void mali_utilization_gp_end(void); ++ ++/** ++ * Should be called when a job is about to execute a PP job ++ */ ++void mali_utilization_pp_start(void); ++ ++/** ++ * Should be called when a job has completed executing a PP job ++ */ ++void mali_utilization_pp_end(void); ++ ++/** ++ * Should be called to stop the utilization timer during system suspend ++ */ ++void mali_utilization_suspend(void); ++ ++ ++#endif /* __MALI_KERNEL_UTILIZATION_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_vsync.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_vsync.c +new file mode 100644 +index 0000000..a329cb0 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_kernel_vsync.c +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_ukk.h" ++ ++#if defined(CONFIG_MALI400_PROFILING) ++#include "mali_osk_profiling.h" ++#endif ++ ++_mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args) ++{ ++ _mali_uk_vsync_event event = (_mali_uk_vsync_event)args->event; ++ MALI_IGNORE(event); /* event is not used for release code, and that is OK */ ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ /* ++ * Manually generate user space events in kernel space. ++ * This saves user space from calling kernel space twice in this case. ++ * We just need to remember to add pid and tid manually. ++ */ ++ if ( event==_MALI_UK_VSYNC_EVENT_BEGIN_WAIT) { ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SUSPEND | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, ++ _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); ++ } ++ ++ if (event==_MALI_UK_VSYNC_EVENT_END_WAIT) { ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_RESUME | ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC, ++ _mali_osk_get_pid(), _mali_osk_get_tid(), 0, 0, 0); ++ } ++#endif ++ ++ MALI_DEBUG_PRINT(4, ("Received VSYNC event: %d\n", event)); ++ MALI_SUCCESS; ++} ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.c +new file mode 100644 +index 0000000..2c6013e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.c +@@ -0,0 +1,581 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_l2_cache.h" ++#include "mali_hw_core.h" ++#include "mali_scheduler.h" ++#include "mali_pm_domain.h" ++ ++/** ++ * Size of the Mali L2 cache registers in bytes ++ */ ++#define MALI400_L2_CACHE_REGISTERS_SIZE 0x30 ++ ++/** ++ * Mali L2 cache register numbers ++ * Used in the register read/write routines. ++ * See the hardware documentation for more information about each register ++ */ ++typedef enum mali_l2_cache_register { ++ MALI400_L2_CACHE_REGISTER_SIZE = 0x0004, ++ MALI400_L2_CACHE_REGISTER_STATUS = 0x0008, ++ /*unused = 0x000C */ ++ MALI400_L2_CACHE_REGISTER_COMMAND = 0x0010, /**< Misc cache commands, e.g. clear */ ++ MALI400_L2_CACHE_REGISTER_CLEAR_PAGE = 0x0014, ++ MALI400_L2_CACHE_REGISTER_MAX_READS = 0x0018, /**< Limit of outstanding read requests */ ++ MALI400_L2_CACHE_REGISTER_ENABLE = 0x001C, /**< Enable misc cache features */ ++ MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0 = 0x0020, ++ MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0 = 0x0024, ++ MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1 = 0x0028, ++ MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1 = 0x002C, ++} mali_l2_cache_register; ++ ++/** ++ * Mali L2 cache commands ++ * These are the commands that can be sent to the Mali L2 cache unit ++ */ ++typedef enum mali_l2_cache_command { ++ MALI400_L2_CACHE_COMMAND_CLEAR_ALL = 0x01, /**< Clear the entire cache */ ++ /* Read HW TRM carefully before adding/using other commands than the clear above */ ++} mali_l2_cache_command; ++ ++/** ++ * Mali L2 cache commands ++ * These are the commands that can be sent to the Mali L2 cache unit ++ */ ++typedef enum mali_l2_cache_enable { ++ MALI400_L2_CACHE_ENABLE_DEFAULT = 0x0, /**< Default state of enable register */ ++ MALI400_L2_CACHE_ENABLE_ACCESS = 0x01, /**< Permit cacheable accesses */ ++ MALI400_L2_CACHE_ENABLE_READ_ALLOCATE = 0x02, /**< Permit cache read allocate */ ++} mali_l2_cache_enable; ++ ++/** ++ * Mali L2 cache status bits ++ */ ++typedef enum mali_l2_cache_status { ++ MALI400_L2_CACHE_STATUS_COMMAND_BUSY = 0x01, /**< Command handler of L2 cache is busy */ ++ MALI400_L2_CACHE_STATUS_DATA_BUSY = 0x02, /**< L2 cache is busy handling data requests */ ++} mali_l2_cache_status; ++ ++#define MALI400_L2_MAX_READS_DEFAULT 0x1C ++ ++static struct mali_l2_cache_core *mali_global_l2_cache_cores[MALI_MAX_NUMBER_OF_L2_CACHE_CORES] = { NULL, }; ++static u32 mali_global_num_l2_cache_cores = 0; ++ ++int mali_l2_max_reads = MALI400_L2_MAX_READS_DEFAULT; ++ ++ ++/* Local helper functions */ ++static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val); ++ ++ ++static void mali_l2_cache_counter_lock(struct mali_l2_cache_core *cache) ++{ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_lock(cache->counter_lock); ++#else ++ _mali_osk_spinlock_lock(cache->counter_lock); ++#endif ++} ++ ++static void mali_l2_cache_counter_unlock(struct mali_l2_cache_core *cache) ++{ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_unlock(cache->counter_lock); ++#else ++ _mali_osk_spinlock_unlock(cache->counter_lock); ++#endif ++} ++ ++static void mali_l2_cache_command_lock(struct mali_l2_cache_core *cache) ++{ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_lock(cache->command_lock); ++#else ++ _mali_osk_spinlock_lock(cache->command_lock); ++#endif ++} ++ ++static void mali_l2_cache_command_unlock(struct mali_l2_cache_core *cache) ++{ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_unlock(cache->command_lock); ++#else ++ _mali_osk_spinlock_unlock(cache->command_lock); ++#endif ++} ++ ++struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t *resource) ++{ ++ struct mali_l2_cache_core *cache = NULL; ++ ++ MALI_DEBUG_PRINT(4, ("Mali L2 cache: Creating Mali L2 cache: %s\n", resource->description)); ++ ++ if (mali_global_num_l2_cache_cores >= MALI_MAX_NUMBER_OF_L2_CACHE_CORES) { ++ MALI_PRINT_ERROR(("Mali L2 cache: Too many L2 cache core objects created\n")); ++ return NULL; ++ } ++ ++ cache = _mali_osk_malloc(sizeof(struct mali_l2_cache_core)); ++ if (NULL != cache) { ++ cache->core_id = mali_global_num_l2_cache_cores; ++ cache->counter_src0 = MALI_HW_CORE_NO_COUNTER; ++ cache->counter_src1 = MALI_HW_CORE_NO_COUNTER; ++ cache->pm_domain = NULL; ++ cache->mali_l2_status = MALI_L2_NORMAL; ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&cache->hw_core, resource, MALI400_L2_CACHE_REGISTERS_SIZE)) { ++ MALI_DEBUG_CODE(u32 cache_size = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_SIZE)); ++ MALI_DEBUG_PRINT(2, ("Mali L2 cache: Created %s: % 3uK, %u-way, % 2ubyte cache line, % 3ubit external bus\n", ++ resource->description, ++ 1 << (((cache_size >> 16) & 0xff) - 10), ++ 1 << ((cache_size >> 8) & 0xff), ++ 1 << (cache_size & 0xff), ++ 1 << ((cache_size >> 24) & 0xff))); ++ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ cache->command_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); ++#else ++ cache->command_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); ++#endif ++ if (NULL != cache->command_lock) { ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ cache->counter_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); ++#else ++ cache->counter_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_L2_COMMAND); ++#endif ++ if (NULL != cache->counter_lock) { ++ mali_l2_cache_reset(cache); ++ ++ cache->last_invalidated_id = 0; ++ ++ mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = cache; ++ mali_global_num_l2_cache_cores++; ++ ++ return cache; ++ } else { ++ MALI_PRINT_ERROR(("Mali L2 cache: Failed to create counter lock for L2 cache core %s\n", cache->hw_core.description)); ++ } ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_term(cache->command_lock); ++#else ++ _mali_osk_spinlock_term(cache->command_lock); ++#endif ++ } else { ++ MALI_PRINT_ERROR(("Mali L2 cache: Failed to create command lock for L2 cache core %s\n", cache->hw_core.description)); ++ } ++ ++ mali_hw_core_delete(&cache->hw_core); ++ } ++ ++ _mali_osk_free(cache); ++ } else { ++ MALI_PRINT_ERROR(("Mali L2 cache: Failed to allocate memory for L2 cache core\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_l2_cache_delete(struct mali_l2_cache_core *cache) ++{ ++ u32 i; ++ ++ /* reset to defaults */ ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)MALI400_L2_MAX_READS_DEFAULT); ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_DEFAULT); ++ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_term(cache->counter_lock); ++ _mali_osk_spinlock_irq_term(cache->command_lock); ++#else ++ _mali_osk_spinlock_term(cache->command_lock); ++ _mali_osk_spinlock_term(cache->counter_lock); ++#endif ++ ++ mali_hw_core_delete(&cache->hw_core); ++ ++ for (i = 0; i < mali_global_num_l2_cache_cores; i++) { ++ if (mali_global_l2_cache_cores[i] == cache) { ++ mali_global_l2_cache_cores[i] = NULL; ++ mali_global_num_l2_cache_cores--; ++ ++ if (i != mali_global_num_l2_cache_cores) { ++ /* We removed a l2 cache from the middle of the array -- move the last ++ * l2 cache to the current position to close the gap */ ++ mali_global_l2_cache_cores[i] = mali_global_l2_cache_cores[mali_global_num_l2_cache_cores]; ++ mali_global_l2_cache_cores[mali_global_num_l2_cache_cores] = NULL; ++ } ++ ++ break; ++ } ++ } ++ ++ _mali_osk_free(cache); ++} ++ ++u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache) ++{ ++ return cache->core_id; ++} ++ ++static void mali_l2_cache_core_set_counter_internal(struct mali_l2_cache_core *cache, u32 source_id, u32 counter) ++{ ++ u32 value = 0; /* disabled src */ ++ u32 reg_offset = 0; ++ mali_bool core_is_on; ++ ++ MALI_DEBUG_ASSERT_POINTER(cache); ++ ++ core_is_on = mali_l2_cache_lock_power_state(cache); ++ ++ mali_l2_cache_counter_lock(cache); ++ ++ switch (source_id) { ++ case 0: ++ cache->counter_src0 = counter; ++ reg_offset = MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0; ++ break; ++ ++ case 1: ++ cache->counter_src1 = counter; ++ reg_offset = MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1; ++ break; ++ ++ default: ++ MALI_DEBUG_ASSERT(0); ++ break; ++ } ++ ++ if (MALI_L2_PAUSE == cache->mali_l2_status) { ++ mali_l2_cache_counter_unlock(cache); ++ mali_l2_cache_unlock_power_state(cache); ++ return; ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter) { ++ value = counter; ++ } ++ ++ if (MALI_TRUE == core_is_on) { ++ mali_hw_core_register_write(&cache->hw_core, reg_offset, value); ++ } ++ ++ mali_l2_cache_counter_unlock(cache); ++ mali_l2_cache_unlock_power_state(cache); ++} ++ ++void mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter) ++{ ++ mali_l2_cache_core_set_counter_internal(cache, 0, counter); ++} ++ ++void mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter) ++{ ++ mali_l2_cache_core_set_counter_internal(cache, 1, counter); ++} ++ ++u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache) ++{ ++ return cache->counter_src0; ++} ++ ++u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache) ++{ ++ return cache->counter_src1; ++} ++ ++void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1) ++{ ++ MALI_DEBUG_ASSERT(NULL != src0); ++ MALI_DEBUG_ASSERT(NULL != value0); ++ MALI_DEBUG_ASSERT(NULL != src1); ++ MALI_DEBUG_ASSERT(NULL != value1); ++ ++ /* Caller must hold the PM lock and know that we are powered on */ ++ ++ mali_l2_cache_counter_lock(cache); ++ ++ if (MALI_L2_PAUSE == cache->mali_l2_status) { ++ mali_l2_cache_counter_unlock(cache); ++ ++ return; ++ } ++ ++ *src0 = cache->counter_src0; ++ *src1 = cache->counter_src1; ++ ++ if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) { ++ *value0 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL0); ++ } ++ ++ if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER) { ++ *value1 = mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_VAL1); ++ } ++ ++ mali_l2_cache_counter_unlock(cache); ++} ++ ++static void mali_l2_cache_reset_counters_all(void) ++{ ++ int i; ++ u32 value; ++ struct mali_l2_cache_core *cache; ++ u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); ++ ++ for (i = 0; i < num_cores; i++) { ++ cache = mali_l2_cache_core_get_glob_l2_core(i); ++ if (MALI_TRUE == mali_l2_cache_lock_power_state(cache)) { ++ mali_l2_cache_counter_lock(cache); ++ ++ if (MALI_L2_PAUSE == cache->mali_l2_status) { ++ mali_l2_cache_counter_unlock(cache); ++ mali_l2_cache_unlock_power_state(cache); ++ return; ++ } ++ ++ /* Reset performance counters */ ++ if (MALI_HW_CORE_NO_COUNTER == cache->counter_src0) { ++ value = 0; ++ } else { ++ value = cache->counter_src0; ++ } ++ mali_hw_core_register_write(&cache->hw_core, ++ MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, value); ++ ++ if (MALI_HW_CORE_NO_COUNTER == cache->counter_src1) { ++ value = 0; ++ } else { ++ value = cache->counter_src1; ++ } ++ mali_hw_core_register_write(&cache->hw_core, ++ MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, value); ++ ++ mali_l2_cache_counter_unlock(cache); ++ } ++ ++ mali_l2_cache_unlock_power_state(cache); ++ } ++} ++ ++ ++struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index) ++{ ++ if (mali_global_num_l2_cache_cores > index) { ++ return mali_global_l2_cache_cores[index]; ++ } ++ ++ return NULL; ++} ++ ++u32 mali_l2_cache_core_get_glob_num_l2_cores(void) ++{ ++ return mali_global_num_l2_cache_cores; ++} ++ ++void mali_l2_cache_reset(struct mali_l2_cache_core *cache) ++{ ++ /* Invalidate cache (just to keep it in a known state at startup) */ ++ mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); ++ ++ mali_l2_cache_counter_lock(cache); ++ ++ if (MALI_L2_PAUSE == cache->mali_l2_status) { ++ mali_l2_cache_counter_unlock(cache); ++ ++ return; ++ } ++ ++ /* Enable cache */ ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_ENABLE, (u32)MALI400_L2_CACHE_ENABLE_ACCESS | (u32)MALI400_L2_CACHE_ENABLE_READ_ALLOCATE); ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_MAX_READS, (u32)mali_l2_max_reads); ++ ++ /* Restart any performance counters (if enabled) */ ++ if (cache->counter_src0 != MALI_HW_CORE_NO_COUNTER) { ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC0, cache->counter_src0); ++ } ++ ++ if (cache->counter_src1 != MALI_HW_CORE_NO_COUNTER) { ++ mali_hw_core_register_write(&cache->hw_core, MALI400_L2_CACHE_REGISTER_PERFCNT_SRC1, cache->counter_src1); ++ } ++ ++ mali_l2_cache_counter_unlock(cache); ++} ++ ++void mali_l2_cache_reset_all(void) ++{ ++ int i; ++ u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); ++ ++ for (i = 0; i < num_cores; i++) { ++ mali_l2_cache_reset(mali_l2_cache_core_get_glob_l2_core(i)); ++ } ++} ++ ++void mali_l2_cache_invalidate(struct mali_l2_cache_core *cache) ++{ ++ MALI_DEBUG_ASSERT_POINTER(cache); ++ ++ if (NULL != cache) { ++ cache->last_invalidated_id = mali_scheduler_get_new_cache_order(); ++ mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); ++ } ++} ++ ++mali_bool mali_l2_cache_invalidate_conditional(struct mali_l2_cache_core *cache, u32 id) ++{ ++ MALI_DEBUG_ASSERT_POINTER(cache); ++ ++ if (NULL != cache) { ++ /* If the last cache invalidation was done by a job with a higher id we ++ * don't have to flush. Since user space will store jobs w/ their ++ * corresponding memory in sequence (first job #0, then job #1, ...), ++ * we don't have to flush for job n-1 if job n has already invalidated ++ * the cache since we know for sure that job n-1's memory was already ++ * written when job n was started. */ ++ if (((s32)id) <= ((s32)cache->last_invalidated_id)) { ++ return MALI_FALSE; ++ } else { ++ cache->last_invalidated_id = mali_scheduler_get_new_cache_order(); ++ } ++ ++ mali_l2_cache_send_command(cache, MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); ++ } ++ return MALI_TRUE; ++} ++ ++void mali_l2_cache_invalidate_all(void) ++{ ++ u32 i; ++ for (i = 0; i < mali_global_num_l2_cache_cores; i++) { ++ /*additional check*/ ++ if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_l2_cache_cores[i])) { ++ _mali_osk_errcode_t ret; ++ mali_global_l2_cache_cores[i]->last_invalidated_id = mali_scheduler_get_new_cache_order(); ++ ret = mali_l2_cache_send_command(mali_global_l2_cache_cores[i], MALI400_L2_CACHE_REGISTER_COMMAND, MALI400_L2_CACHE_COMMAND_CLEAR_ALL); ++ if (_MALI_OSK_ERR_OK != ret) { ++ MALI_PRINT_ERROR(("Failed to invalidate cache\n")); ++ } ++ } ++ mali_l2_cache_unlock_power_state(mali_global_l2_cache_cores[i]); ++ } ++} ++ ++void mali_l2_cache_invalidate_all_pages(u32 *pages, u32 num_pages) ++{ ++ u32 i; ++ for (i = 0; i < mali_global_num_l2_cache_cores; i++) { ++ /*additional check*/ ++ if (MALI_TRUE == mali_l2_cache_lock_power_state(mali_global_l2_cache_cores[i])) { ++ u32 j; ++ for (j = 0; j < num_pages; j++) { ++ _mali_osk_errcode_t ret; ++ ret = mali_l2_cache_send_command(mali_global_l2_cache_cores[i], MALI400_L2_CACHE_REGISTER_CLEAR_PAGE, pages[j]); ++ if (_MALI_OSK_ERR_OK != ret) { ++ MALI_PRINT_ERROR(("Failed to invalidate page cache\n")); ++ } ++ } ++ } ++ mali_l2_cache_unlock_power_state(mali_global_l2_cache_cores[i]); ++ } ++} ++ ++mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache) ++{ ++ return mali_pm_domain_lock_state(cache->pm_domain); ++} ++ ++void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache) ++{ ++ return mali_pm_domain_unlock_state(cache->pm_domain); ++} ++ ++/* -------- local helper functions below -------- */ ++ ++ ++static _mali_osk_errcode_t mali_l2_cache_send_command(struct mali_l2_cache_core *cache, u32 reg, u32 val) ++{ ++ int i = 0; ++ const int loop_count = 100000; ++ ++ /* ++ * Grab lock in order to send commands to the L2 cache in a serialized fashion. ++ * The L2 cache will ignore commands if it is busy. ++ */ ++ mali_l2_cache_command_lock(cache); ++ ++ if (MALI_L2_PAUSE == cache->mali_l2_status) { ++ mali_l2_cache_command_unlock(cache); ++ MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for L2 come back\n")); ++ ++ MALI_ERROR( _MALI_OSK_ERR_BUSY ); ++ } ++ ++ /* First, wait for L2 cache command handler to go idle */ ++ ++ for (i = 0; i < loop_count; i++) { ++ if (!(mali_hw_core_register_read(&cache->hw_core, MALI400_L2_CACHE_REGISTER_STATUS) & (u32)MALI400_L2_CACHE_STATUS_COMMAND_BUSY)) { ++ break; ++ } ++ } ++ ++ if (i == loop_count) { ++ mali_l2_cache_command_unlock(cache); ++ MALI_DEBUG_PRINT(1, ( "Mali L2 cache: aborting wait for command interface to go idle\n")); ++ MALI_ERROR( _MALI_OSK_ERR_FAULT ); ++ } ++ ++ /* then issue the command */ ++ mali_hw_core_register_write(&cache->hw_core, reg, val); ++ ++ mali_l2_cache_command_unlock(cache); ++ ++ MALI_SUCCESS; ++} ++ ++void mali_l2_cache_pause_all(mali_bool pause) ++{ ++ int i; ++ struct mali_l2_cache_core * cache; ++ u32 num_cores = mali_l2_cache_core_get_glob_num_l2_cores(); ++ mali_l2_power_status status = MALI_L2_NORMAL; ++ ++ if (pause) { ++ status = MALI_L2_PAUSE; ++ } ++ ++ for (i = 0; i < num_cores; i++) { ++ cache = mali_l2_cache_core_get_glob_l2_core(i); ++ if (NULL != cache) { ++ cache->mali_l2_status = status; ++ ++ /* Take and release the counter and command locks to ++ * ensure there are no active threads that didn't get ++ * the status flag update. ++ * ++ * The locks will also ensure the necessary memory ++ * barriers are done on SMP systems. ++ */ ++ mali_l2_cache_counter_lock(cache); ++ mali_l2_cache_counter_unlock(cache); ++ ++ mali_l2_cache_command_lock(cache); ++ mali_l2_cache_command_unlock(cache); ++ } ++ } ++ ++ /* Resume from pause: do the cache invalidation here to prevent any ++ * loss of cache operation during the pause period to make sure the SW ++ * status is consistent with L2 cache status. ++ */ ++ if(!pause) { ++ mali_l2_cache_invalidate_all(); ++ mali_l2_cache_reset_counters_all(); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.h +new file mode 100644 +index 0000000..afa7b82 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_l2_cache.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_L2_CACHE_H__ ++#define __MALI_KERNEL_L2_CACHE_H__ ++ ++#include "mali_osk.h" ++#include "mali_hw_core.h" ++ ++#define MALI_MAX_NUMBER_OF_L2_CACHE_CORES 3 ++/* Maximum 1 GP and 4 PP for an L2 cache core (Mali-400 Quad-core) */ ++#define MALI_MAX_NUMBER_OF_GROUPS_PER_L2_CACHE 5 ++ ++struct mali_group; ++struct mali_pm_domain; ++ ++/* Flags describing state of the L2 */ ++typedef enum mali_l2_power_status { ++ MALI_L2_NORMAL, /**< L2 is in normal state and operational */ ++ MALI_L2_PAUSE, /**< L2 may not be accessed and may be powered off */ ++} mali_l2_power_status; ++ ++/** ++ * Definition of the L2 cache core struct ++ * Used to track a L2 cache unit in the system. ++ * Contains information about the mapping of the registers ++ */ ++struct mali_l2_cache_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ u32 core_id; /**< Unique core ID */ ++#ifdef MALI_UPPER_HALF_SCHEDULING ++ _mali_osk_spinlock_irq_t *command_lock; /**< Serialize all L2 cache commands */ ++ _mali_osk_spinlock_irq_t *counter_lock; /**< Synchronize L2 cache counter access */ ++#else ++ _mali_osk_spinlock_t *command_lock; ++ _mali_osk_spinlock_t *counter_lock; ++#endif ++ u32 counter_src0; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ ++ u32 counter_src1; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ ++ u32 last_invalidated_id; ++ struct mali_pm_domain *pm_domain; ++ mali_l2_power_status mali_l2_status; /**< Indicate whether the L2 is paused or not */ ++}; ++ ++_mali_osk_errcode_t mali_l2_cache_initialize(void); ++void mali_l2_cache_terminate(void); ++/** ++ * L2 pause is just a status that the L2 can't be accessed temporarily. ++*/ ++void mali_l2_cache_pause_all(mali_bool pause); ++struct mali_l2_cache_core *mali_l2_cache_create(_mali_osk_resource_t * resource); ++void mali_l2_cache_delete(struct mali_l2_cache_core *cache); ++ ++MALI_STATIC_INLINE void mali_l2_cache_set_pm_domain(struct mali_l2_cache_core *cache, struct mali_pm_domain *domain) ++{ ++ cache->pm_domain = domain; ++} ++ ++u32 mali_l2_cache_get_id(struct mali_l2_cache_core *cache); ++ ++void mali_l2_cache_core_set_counter_src0(struct mali_l2_cache_core *cache, u32 counter); ++void mali_l2_cache_core_set_counter_src1(struct mali_l2_cache_core *cache, u32 counter); ++u32 mali_l2_cache_core_get_counter_src0(struct mali_l2_cache_core *cache); ++u32 mali_l2_cache_core_get_counter_src1(struct mali_l2_cache_core *cache); ++void mali_l2_cache_core_get_counter_values(struct mali_l2_cache_core *cache, u32 *src0, u32 *value0, u32 *src1, u32 *value1); ++struct mali_l2_cache_core *mali_l2_cache_core_get_glob_l2_core(u32 index); ++u32 mali_l2_cache_core_get_glob_num_l2_cores(void); ++ ++void mali_l2_cache_reset(struct mali_l2_cache_core *cache); ++void mali_l2_cache_reset_all(void); ++ ++struct mali_group *mali_l2_cache_get_group(struct mali_l2_cache_core *cache, u32 index); ++ ++void mali_l2_cache_invalidate(struct mali_l2_cache_core *cache); ++mali_bool mali_l2_cache_invalidate_conditional(struct mali_l2_cache_core *cache, u32 id); ++void mali_l2_cache_invalidate_all(void); ++void mali_l2_cache_invalidate_all_pages(u32 *pages, u32 num_pages); ++ ++mali_bool mali_l2_cache_lock_power_state(struct mali_l2_cache_core *cache); ++void mali_l2_cache_unlock_power_state(struct mali_l2_cache_core *cache); ++ ++#endif /* __MALI_KERNEL_L2_CACHE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.c +new file mode 100644 +index 0000000..c72eb74 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.c +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_mem_validation.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++#define MALI_INVALID_MEM_ADDR 0xFFFFFFFF ++ ++typedef struct { ++ u32 phys_base; /**< Mali physical base of the memory, page aligned */ ++ u32 size; /**< size in bytes of the memory, multiple of page size */ ++} _mali_mem_validation_t; ++ ++static _mali_mem_validation_t mali_mem_validator = { MALI_INVALID_MEM_ADDR, MALI_INVALID_MEM_ADDR }; ++ ++_mali_osk_errcode_t mali_mem_validation_add_range(u32 start, u32 size) ++{ ++ /* Check that no other MEM_VALIDATION resources exist */ ++ if (MALI_INVALID_MEM_ADDR != mali_mem_validator.phys_base) { ++ MALI_PRINT_ERROR(("Failed to add frame buffer memory; another range is already specified\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Check restrictions on page alignment */ ++ if ((0 != (start & (~_MALI_OSK_CPU_PAGE_MASK))) || ++ (0 != (size & (~_MALI_OSK_CPU_PAGE_MASK)))) { ++ MALI_PRINT_ERROR(("Failed to add frame buffer memory; incorrect alignment\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ mali_mem_validator.phys_base = start; ++ mali_mem_validator.size = size; ++ MALI_DEBUG_PRINT(2, ("Memory Validator installed for Mali physical address base=0x%08X, size=0x%08X\n", ++ mali_mem_validator.phys_base, mali_mem_validator.size)); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size) ++{ ++ if (phys_addr < (phys_addr + size)) { /* Don't allow overflow (or zero size) */ ++ if ((0 == ( phys_addr & (~_MALI_OSK_CPU_PAGE_MASK))) && ++ (0 == ( size & (~_MALI_OSK_CPU_PAGE_MASK)))) { ++ if ((phys_addr >= mali_mem_validator.phys_base) && ++ ((phys_addr + (size - 1)) >= mali_mem_validator.phys_base) && ++ (phys_addr <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) && ++ ((phys_addr + (size - 1)) <= (mali_mem_validator.phys_base + (mali_mem_validator.size - 1))) ) { ++ MALI_DEBUG_PRINT(3, ("Accepted range 0x%08X + size 0x%08X (= 0x%08X)\n", phys_addr, size, (phys_addr + size - 1))); ++ return _MALI_OSK_ERR_OK; ++ } ++ } ++ } ++ ++ MALI_PRINT_ERROR(("MALI PHYSICAL RANGE VALIDATION ERROR: The range supplied was: phys_base=0x%08X, size=0x%08X\n", phys_addr, size)); ++ ++ return _MALI_OSK_ERR_FAULT; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.h +new file mode 100644 +index 0000000..a9ab6d4 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mem_validation.h +@@ -0,0 +1,19 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MEM_VALIDATION_H__ ++#define __MALI_MEM_VALIDATION_H__ ++ ++#include "mali_osk.h" ++ ++_mali_osk_errcode_t mali_mem_validation_add_range(u32 start, u32 size); ++_mali_osk_errcode_t mali_mem_validation_check(u32 phys_addr, u32 size); ++ ++#endif /* __MALI_MEM_VALIDATION_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.c +new file mode 100644 +index 0000000..896325c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.c +@@ -0,0 +1,430 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_ukk.h" ++ ++#include "mali_mmu.h" ++#include "mali_hw_core.h" ++#include "mali_group.h" ++#include "mali_mmu_page_directory.h" ++ ++/** ++ * Size of the MMU registers in bytes ++ */ ++#define MALI_MMU_REGISTERS_SIZE 0x24 ++ ++/** ++ * MMU commands ++ * These are the commands that can be sent ++ * to the MMU unit. ++ */ ++typedef enum mali_mmu_command { ++ MALI_MMU_COMMAND_ENABLE_PAGING = 0x00, /**< Enable paging (memory translation) */ ++ MALI_MMU_COMMAND_DISABLE_PAGING = 0x01, /**< Disable paging (memory translation) */ ++ MALI_MMU_COMMAND_ENABLE_STALL = 0x02, /**< Enable stall on page fault */ ++ MALI_MMU_COMMAND_DISABLE_STALL = 0x03, /**< Disable stall on page fault */ ++ MALI_MMU_COMMAND_ZAP_CACHE = 0x04, /**< Zap the entire page table cache */ ++ MALI_MMU_COMMAND_PAGE_FAULT_DONE = 0x05, /**< Page fault processed */ ++ MALI_MMU_COMMAND_HARD_RESET = 0x06 /**< Reset the MMU back to power-on settings */ ++} mali_mmu_command; ++ ++static void mali_mmu_probe_trigger(void *data); ++static _mali_osk_errcode_t mali_mmu_probe_ack(void *data); ++ ++MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu); ++ ++/* page fault queue flush helper pages ++ * note that the mapping pointers are currently unused outside of the initialization functions */ ++static u32 mali_page_fault_flush_page_directory = MALI_INVALID_PAGE; ++static mali_io_address mali_page_fault_flush_page_directory_mapping = NULL; ++static u32 mali_page_fault_flush_page_table = MALI_INVALID_PAGE; ++static mali_io_address mali_page_fault_flush_page_table_mapping = NULL; ++static u32 mali_page_fault_flush_data_page = MALI_INVALID_PAGE; ++static mali_io_address mali_page_fault_flush_data_page_mapping = NULL; ++ ++/* an empty page directory (no address valid) which is active on any MMU not currently marked as in use */ ++static u32 mali_empty_page_directory_phys = MALI_INVALID_PAGE; ++static mali_io_address mali_empty_page_directory_virt = NULL; ++ ++ ++_mali_osk_errcode_t mali_mmu_initialize(void) ++{ ++ /* allocate the helper pages */ ++ mali_empty_page_directory_phys = mali_allocate_empty_page(&mali_empty_page_directory_virt); ++ if(0 == mali_empty_page_directory_phys) { ++ MALI_DEBUG_PRINT_ERROR(("Mali MMU: Could not allocate empty page directory.\n")); ++ mali_empty_page_directory_phys = MALI_INVALID_PAGE; ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_create_fault_flush_pages(&mali_page_fault_flush_page_directory, ++ &mali_page_fault_flush_page_directory_mapping, ++ &mali_page_fault_flush_page_table, ++ &mali_page_fault_flush_page_table_mapping, ++ &mali_page_fault_flush_data_page, ++ &mali_page_fault_flush_data_page_mapping)) { ++ MALI_DEBUG_PRINT_ERROR(("Mali MMU: Could not allocate fault flush pages\n")); ++ mali_free_empty_page(mali_empty_page_directory_phys, mali_empty_page_directory_virt); ++ mali_empty_page_directory_phys = MALI_INVALID_PAGE; ++ mali_empty_page_directory_virt = NULL; ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_mmu_terminate(void) ++{ ++ MALI_DEBUG_PRINT(3, ("Mali MMU: terminating\n")); ++ ++ /* Free global helper pages */ ++ mali_free_empty_page(mali_empty_page_directory_phys, mali_empty_page_directory_virt); ++ mali_empty_page_directory_phys = MALI_INVALID_PAGE; ++ mali_empty_page_directory_virt = NULL; ++ ++ /* Free the page fault flush pages */ ++ mali_destroy_fault_flush_pages(&mali_page_fault_flush_page_directory, &mali_page_fault_flush_page_directory_mapping, ++ &mali_page_fault_flush_page_table, &mali_page_fault_flush_page_table_mapping, ++ &mali_page_fault_flush_data_page, &mali_page_fault_flush_data_page_mapping); ++} ++ ++struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource, struct mali_group *group, mali_bool is_virtual) ++{ ++ struct mali_mmu_core* mmu = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(resource); ++ ++ MALI_DEBUG_PRINT(2, ("Mali MMU: Creating Mali MMU: %s\n", resource->description)); ++ ++ mmu = _mali_osk_calloc(1,sizeof(struct mali_mmu_core)); ++ if (NULL != mmu) { ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&mmu->hw_core, resource, MALI_MMU_REGISTERS_SIZE)) { ++ if (_MALI_OSK_ERR_OK == mali_group_add_mmu_core(group, mmu)) { ++ if (is_virtual) { ++ /* Skip reset and IRQ setup for virtual MMU */ ++ return mmu; ++ } ++ ++ if (_MALI_OSK_ERR_OK == mali_mmu_reset(mmu)) { ++ /* Setup IRQ handlers (which will do IRQ probing if needed) */ ++ mmu->irq = _mali_osk_irq_init(resource->irq, ++ mali_group_upper_half_mmu, ++ group, ++ mali_mmu_probe_trigger, ++ mali_mmu_probe_ack, ++ mmu, ++ resource->description); ++ if (NULL != mmu->irq) { ++ return mmu; ++ } else { ++ MALI_PRINT_ERROR(("Mali MMU: Failed to setup interrupt handlers for MMU %s\n", mmu->hw_core.description)); ++ } ++ } ++ mali_group_remove_mmu_core(group); ++ } else { ++ MALI_PRINT_ERROR(("Mali MMU: Failed to add core %s to group\n", mmu->hw_core.description)); ++ } ++ mali_hw_core_delete(&mmu->hw_core); ++ } ++ ++ _mali_osk_free(mmu); ++ } else { ++ MALI_PRINT_ERROR(("Failed to allocate memory for MMU\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_mmu_delete(struct mali_mmu_core *mmu) ++{ ++ if (NULL != mmu->irq) { ++ _mali_osk_irq_term(mmu->irq); ++ } ++ ++ mali_hw_core_delete(&mmu->hw_core); ++ _mali_osk_free(mmu); ++} ++ ++static void mali_mmu_enable_paging(struct mali_mmu_core *mmu) ++{ ++ int i; ++ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_PAGING); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) { ++ if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) & MALI_MMU_STATUS_BIT_PAGING_ENABLED) { ++ break; ++ } ++ } ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Enable paging request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); ++ } ++} ++ ++/** ++ * Issues the enable stall command to the MMU and waits for HW to complete the request ++ * @param mmu The MMU to enable paging for ++ * @return MALI_TRUE if HW stall was successfully engaged, otherwise MALI_FALSE (req timed out) ++ */ ++static mali_bool mali_mmu_enable_stall(struct mali_mmu_core *mmu) ++{ ++ int i; ++ u32 mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); ++ ++ if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED) ) { ++ MALI_DEBUG_PRINT(4, ("MMU stall is implicit when Paging is not enabled.\n")); ++ return MALI_TRUE; ++ } ++ ++ if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) { ++ MALI_DEBUG_PRINT(3, ("Aborting MMU stall request since it is in pagefault state.\n")); ++ return MALI_FALSE; ++ } ++ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ENABLE_STALL); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) { ++ mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); ++ if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) { ++ break; ++ } ++ if ((mmu_status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) && (0 == (mmu_status & MALI_MMU_STATUS_BIT_STALL_NOT_ACTIVE))) { ++ break; ++ } ++ if (0 == (mmu_status & ( MALI_MMU_STATUS_BIT_PAGING_ENABLED ))) { ++ break; ++ } ++ } ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_DEBUG_PRINT(2, ("Enable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); ++ return MALI_FALSE; ++ } ++ ++ if ( mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) { ++ MALI_DEBUG_PRINT(2, ("Aborting MMU stall request since it has a pagefault.\n")); ++ return MALI_FALSE; ++ } ++ ++ return MALI_TRUE; ++} ++ ++/** ++ * Issues the disable stall command to the MMU and waits for HW to complete the request ++ * @param mmu The MMU to enable paging for ++ */ ++static void mali_mmu_disable_stall(struct mali_mmu_core *mmu) ++{ ++ int i; ++ u32 mmu_status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); ++ ++ if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) { ++ MALI_DEBUG_PRINT(3, ("MMU disable skipped since it was not enabled.\n")); ++ return; ++ } ++ if (mmu_status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) { ++ MALI_DEBUG_PRINT(2, ("Aborting MMU disable stall request since it is in pagefault state.\n")); ++ return; ++ } ++ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_DISABLE_STALL); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) { ++ u32 status = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); ++ if ( 0 == (status & MALI_MMU_STATUS_BIT_STALL_ACTIVE) ) { ++ break; ++ } ++ if ( status & MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE ) { ++ break; ++ } ++ if ( 0 == (mmu_status & MALI_MMU_STATUS_BIT_PAGING_ENABLED )) { ++ break; ++ } ++ } ++ if (MALI_REG_POLL_COUNT_FAST == i) MALI_DEBUG_PRINT(1,("Disable stall request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); ++} ++ ++void mali_mmu_page_fault_done(struct mali_mmu_core *mmu) ++{ ++ MALI_DEBUG_PRINT(4, ("Mali MMU: %s: Leaving page fault mode\n", mmu->hw_core.description)); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_PAGE_FAULT_DONE); ++} ++ ++MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_raw_reset(struct mali_mmu_core *mmu) ++{ ++ int i; ++ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, 0xCAFEBABE); ++ MALI_DEBUG_ASSERT(0xCAFEB000 == mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR)); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_HARD_RESET); ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; ++i) { ++ if (mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR) == 0) { ++ break; ++ } ++ } ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Reset request failed, MMU status is 0x%08X\n", mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu) ++{ ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_FAULT; ++ mali_bool stall_success; ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ ++ stall_success = mali_mmu_enable_stall(mmu); ++ if (!stall_success) { ++ err = _MALI_OSK_ERR_BUSY; ++ } ++ ++ MALI_DEBUG_PRINT(3, ("Mali MMU: mali_kernel_mmu_reset: %s\n", mmu->hw_core.description)); ++ ++ if (_MALI_OSK_ERR_OK == mali_mmu_raw_reset(mmu)) { ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, MALI_MMU_INTERRUPT_PAGE_FAULT | MALI_MMU_INTERRUPT_READ_BUS_ERROR); ++ /* no session is active, so just activate the empty page directory */ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, mali_empty_page_directory_phys); ++ mali_mmu_enable_paging(mmu); ++ err = _MALI_OSK_ERR_OK; ++ } ++ mali_mmu_disable_stall(mmu); ++ ++ return err; ++} ++ ++mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu) ++{ ++ mali_bool stall_success = mali_mmu_enable_stall(mmu); ++ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); ++ ++ if (MALI_FALSE == stall_success) { ++ /* False means that it is in Pagefault state. Not possible to disable_stall then */ ++ return MALI_FALSE; ++ } ++ ++ mali_mmu_disable_stall(mmu); ++ return MALI_TRUE; ++} ++ ++void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu) ++{ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); ++} ++ ++ ++void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address) ++{ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_ZAP_ONE_LINE, MALI_MMU_PDE_ENTRY(mali_address)); ++} ++ ++static void mali_mmu_activate_address_space(struct mali_mmu_core *mmu, u32 page_directory) ++{ ++ /* The MMU must be in stalled or page fault mode, for this writing to work */ ++ MALI_DEBUG_ASSERT( 0 != ( mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS) ++ & (MALI_MMU_STATUS_BIT_STALL_ACTIVE|MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE) ) ); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_DTE_ADDR, page_directory); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_COMMAND, MALI_MMU_COMMAND_ZAP_CACHE); ++ ++} ++ ++void mali_mmu_activate_page_directory(struct mali_mmu_core *mmu, struct mali_page_directory *pagedir) ++{ ++ mali_bool stall_success; ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ ++ MALI_DEBUG_PRINT(5, ("Asked to activate page directory 0x%x on MMU %s\n", pagedir, mmu->hw_core.description)); ++ ++ stall_success = mali_mmu_enable_stall(mmu); ++ MALI_DEBUG_ASSERT(stall_success); ++ MALI_IGNORE(stall_success); ++ mali_mmu_activate_address_space(mmu, pagedir->page_directory); ++ mali_mmu_disable_stall(mmu); ++} ++ ++void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu) ++{ ++ mali_bool stall_success; ++ ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ MALI_DEBUG_PRINT(3, ("Activating the empty page directory on MMU %s\n", mmu->hw_core.description)); ++ ++ stall_success = mali_mmu_enable_stall(mmu); ++ ++ /* This function can only be called when the core is idle, so it could not fail. */ ++ MALI_DEBUG_ASSERT(stall_success); ++ MALI_IGNORE(stall_success); ++ ++ mali_mmu_activate_address_space(mmu, mali_empty_page_directory_phys); ++ mali_mmu_disable_stall(mmu); ++} ++ ++void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu) ++{ ++ mali_bool stall_success; ++ MALI_DEBUG_ASSERT_POINTER(mmu); ++ ++ MALI_DEBUG_PRINT(3, ("Activating the page fault flush page directory on MMU %s\n", mmu->hw_core.description)); ++ stall_success = mali_mmu_enable_stall(mmu); ++ /* This function is expect to fail the stalling, since it might be in PageFault mode when it is called */ ++ mali_mmu_activate_address_space(mmu, mali_page_fault_flush_page_directory); ++ if ( MALI_TRUE==stall_success ) mali_mmu_disable_stall(mmu); ++} ++ ++/* Is called when we want the mmu to give an interrupt */ ++static void mali_mmu_probe_trigger(void *data) ++{ ++ struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT, MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR); ++} ++ ++/* Is called when the irq probe wants the mmu to acknowledge an interrupt from the hw */ ++static _mali_osk_errcode_t mali_mmu_probe_ack(void *data) ++{ ++ struct mali_mmu_core *mmu = (struct mali_mmu_core *)data; ++ u32 int_stat; ++ ++ int_stat = mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); ++ ++ MALI_DEBUG_PRINT(2, ("mali_mmu_probe_irq_acknowledge: intstat 0x%x\n", int_stat)); ++ if (int_stat & MALI_MMU_INTERRUPT_PAGE_FAULT) { ++ MALI_DEBUG_PRINT(2, ("Probe: Page fault detect: PASSED\n")); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_PAGE_FAULT); ++ } else { ++ MALI_DEBUG_PRINT(1, ("Probe: Page fault detect: FAILED\n")); ++ } ++ ++ if (int_stat & MALI_MMU_INTERRUPT_READ_BUS_ERROR) { ++ MALI_DEBUG_PRINT(2, ("Probe: Bus read error detect: PASSED\n")); ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_CLEAR, MALI_MMU_INTERRUPT_READ_BUS_ERROR); ++ } else { ++ MALI_DEBUG_PRINT(1, ("Probe: Bus read error detect: FAILED\n")); ++ } ++ ++ if ( (int_stat & (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) == ++ (MALI_MMU_INTERRUPT_PAGE_FAULT|MALI_MMU_INTERRUPT_READ_BUS_ERROR)) { ++ return _MALI_OSK_ERR_OK; ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++#if 0 ++void mali_mmu_print_state(struct mali_mmu_core *mmu) ++{ ++ MALI_DEBUG_PRINT(2, ("MMU: State of %s is 0x%08x\n", mmu->hw_core.description, mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS))); ++} ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.h +new file mode 100644 +index 0000000..1e04e93 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu.h +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MMU_H__ ++#define __MALI_MMU_H__ ++ ++#include "mali_osk.h" ++#include "mali_mmu_page_directory.h" ++#include "mali_hw_core.h" ++ ++/* Forward declaration from mali_group.h */ ++struct mali_group; ++ ++/** ++ * MMU register numbers ++ * Used in the register read/write routines. ++ * See the hardware documentation for more information about each register ++ */ ++typedef enum mali_mmu_register { ++ MALI_MMU_REGISTER_DTE_ADDR = 0x0000, /**< Current Page Directory Pointer */ ++ MALI_MMU_REGISTER_STATUS = 0x0004, /**< Status of the MMU */ ++ MALI_MMU_REGISTER_COMMAND = 0x0008, /**< Command register, used to control the MMU */ ++ MALI_MMU_REGISTER_PAGE_FAULT_ADDR = 0x000C, /**< Logical address of the last page fault */ ++ MALI_MMU_REGISTER_ZAP_ONE_LINE = 0x010, /**< Used to invalidate the mapping of a single page from the MMU */ ++ MALI_MMU_REGISTER_INT_RAWSTAT = 0x0014, /**< Raw interrupt status, all interrupts visible */ ++ MALI_MMU_REGISTER_INT_CLEAR = 0x0018, /**< Indicate to the MMU that the interrupt has been received */ ++ MALI_MMU_REGISTER_INT_MASK = 0x001C, /**< Enable/disable types of interrupts */ ++ MALI_MMU_REGISTER_INT_STATUS = 0x0020 /**< Interrupt status based on the mask */ ++} mali_mmu_register; ++ ++/** ++ * MMU interrupt register bits ++ * Each cause of the interrupt is reported ++ * through the (raw) interrupt status registers. ++ * Multiple interrupts can be pending, so multiple bits ++ * can be set at once. ++ */ ++typedef enum mali_mmu_interrupt { ++ MALI_MMU_INTERRUPT_PAGE_FAULT = 0x01, /**< A page fault occured */ ++ MALI_MMU_INTERRUPT_READ_BUS_ERROR = 0x02 /**< A bus read error occured */ ++} mali_mmu_interrupt; ++ ++typedef enum mali_mmu_status_bits { ++ MALI_MMU_STATUS_BIT_PAGING_ENABLED = 1 << 0, ++ MALI_MMU_STATUS_BIT_PAGE_FAULT_ACTIVE = 1 << 1, ++ MALI_MMU_STATUS_BIT_STALL_ACTIVE = 1 << 2, ++ MALI_MMU_STATUS_BIT_IDLE = 1 << 3, ++ MALI_MMU_STATUS_BIT_REPLAY_BUFFER_EMPTY = 1 << 4, ++ MALI_MMU_STATUS_BIT_PAGE_FAULT_IS_WRITE = 1 << 5, ++ MALI_MMU_STATUS_BIT_STALL_NOT_ACTIVE = 1 << 31, ++} mali_mmu_status_bits; ++ ++/** ++ * Definition of the MMU struct ++ * Used to track a MMU unit in the system. ++ * Contains information about the mapping of the registers ++ */ ++struct mali_mmu_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ _mali_osk_irq_t *irq; /**< IRQ handler */ ++}; ++ ++_mali_osk_errcode_t mali_mmu_initialize(void); ++ ++void mali_mmu_terminate(void); ++ ++struct mali_mmu_core *mali_mmu_create(_mali_osk_resource_t *resource, struct mali_group *group, mali_bool is_virtual); ++void mali_mmu_delete(struct mali_mmu_core *mmu); ++ ++_mali_osk_errcode_t mali_mmu_reset(struct mali_mmu_core *mmu); ++mali_bool mali_mmu_zap_tlb(struct mali_mmu_core *mmu); ++void mali_mmu_zap_tlb_without_stall(struct mali_mmu_core *mmu); ++void mali_mmu_invalidate_page(struct mali_mmu_core *mmu, u32 mali_address); ++ ++void mali_mmu_activate_page_directory(struct mali_mmu_core* mmu, struct mali_page_directory *pagedir); ++void mali_mmu_activate_empty_page_directory(struct mali_mmu_core* mmu); ++void mali_mmu_activate_fault_flush_page_directory(struct mali_mmu_core* mmu); ++ ++void mali_mmu_page_fault_done(struct mali_mmu_core *mmu); ++ ++/*** Register reading/writing functions ***/ ++MALI_STATIC_INLINE u32 mali_mmu_get_int_status(struct mali_mmu_core *mmu) ++{ ++ return mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_STATUS); ++} ++ ++MALI_STATIC_INLINE u32 mali_mmu_get_rawstat(struct mali_mmu_core *mmu) ++{ ++ return mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_INT_RAWSTAT); ++} ++ ++MALI_STATIC_INLINE void mali_mmu_mask_all_interrupts(struct mali_mmu_core *mmu) ++{ ++ mali_hw_core_register_write(&mmu->hw_core, MALI_MMU_REGISTER_INT_MASK, 0); ++} ++ ++MALI_STATIC_INLINE u32 mali_mmu_get_status(struct mali_mmu_core *mmu) ++{ ++ return mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_STATUS); ++} ++ ++MALI_STATIC_INLINE u32 mali_mmu_get_page_fault_addr(struct mali_mmu_core *mmu) ++{ ++ return mali_hw_core_register_read(&mmu->hw_core, MALI_MMU_REGISTER_PAGE_FAULT_ADDR); ++} ++ ++#endif /* __MALI_MMU_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.c +new file mode 100644 +index 0000000..3e82df2 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.c +@@ -0,0 +1,436 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_uk_types.h" ++#include "mali_mmu_page_directory.h" ++#include "mali_memory.h" ++#include "mali_l2_cache.h" ++ ++static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data); ++ ++u32 mali_allocate_empty_page(mali_io_address *virt_addr) ++{ ++ _mali_osk_errcode_t err; ++ mali_io_address mapping; ++ u32 address; ++ ++ if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&address, &mapping)) { ++ /* Allocation failed */ ++ MALI_DEBUG_PRINT(2, ("Mali MMU: Failed to get table page for empty pgdir\n")); ++ return 0; ++ } ++ ++ MALI_DEBUG_ASSERT_POINTER( mapping ); ++ ++ err = fill_page(mapping, 0); ++ if (_MALI_OSK_ERR_OK != err) { ++ mali_mmu_release_table_page(address, mapping); ++ MALI_DEBUG_PRINT(2, ("Mali MMU: Failed to zero page\n")); ++ return 0; ++ } ++ ++ *virt_addr = mapping; ++ return address; ++} ++ ++void mali_free_empty_page(u32 address, mali_io_address virt_addr) ++{ ++ if (MALI_INVALID_PAGE != address) { ++ mali_mmu_release_table_page(address, virt_addr); ++ } ++} ++ ++_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, mali_io_address *page_directory_mapping, ++ u32 *page_table, mali_io_address *page_table_mapping, ++ u32 *data_page, mali_io_address *data_page_mapping) ++{ ++ _mali_osk_errcode_t err; ++ ++ err = mali_mmu_get_table_page(data_page, data_page_mapping); ++ if (_MALI_OSK_ERR_OK == err) { ++ err = mali_mmu_get_table_page(page_table, page_table_mapping); ++ if (_MALI_OSK_ERR_OK == err) { ++ err = mali_mmu_get_table_page(page_directory, page_directory_mapping); ++ if (_MALI_OSK_ERR_OK == err) { ++ fill_page(*data_page_mapping, 0); ++ fill_page(*page_table_mapping, *data_page | MALI_MMU_FLAGS_DEFAULT); ++ fill_page(*page_directory_mapping, *page_table | MALI_MMU_FLAGS_PRESENT); ++ MALI_SUCCESS; ++ } ++ mali_mmu_release_table_page(*page_table, *page_table_mapping); ++ *page_table = MALI_INVALID_PAGE; ++ } ++ mali_mmu_release_table_page(*data_page, *data_page_mapping); ++ *data_page = MALI_INVALID_PAGE; ++ } ++ return err; ++} ++ ++void mali_destroy_fault_flush_pages(u32 *page_directory, mali_io_address *page_directory_mapping, ++ u32 *page_table, mali_io_address *page_table_mapping, ++ u32 *data_page, mali_io_address *data_page_mapping) ++{ ++ if (MALI_INVALID_PAGE != *page_directory) { ++ mali_mmu_release_table_page(*page_directory, *page_directory_mapping); ++ *page_directory = MALI_INVALID_PAGE; ++ *page_directory_mapping = NULL; ++ } ++ ++ if (MALI_INVALID_PAGE != *page_table) { ++ mali_mmu_release_table_page(*page_table, *page_table_mapping); ++ *page_table = MALI_INVALID_PAGE; ++ *page_table_mapping = NULL; ++ } ++ ++ if (MALI_INVALID_PAGE != *data_page) { ++ mali_mmu_release_table_page(*data_page, *data_page_mapping); ++ *data_page = MALI_INVALID_PAGE; ++ *data_page_mapping = NULL; ++ } ++} ++ ++static _mali_osk_errcode_t fill_page(mali_io_address mapping, u32 data) ++{ ++ int i; ++ MALI_DEBUG_ASSERT_POINTER( mapping ); ++ ++ for(i = 0; i < MALI_MMU_PAGE_SIZE/4; i++) { ++ _mali_osk_mem_iowrite32_relaxed( mapping, i * sizeof(u32), data); ++ } ++ _mali_osk_mem_barrier(); ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size) ++{ ++ const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); ++ const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); ++ _mali_osk_errcode_t err; ++ mali_io_address pde_mapping; ++ u32 pde_phys; ++ int i; ++ ++ if (last_pde < first_pde) { ++ MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); ++ } ++ ++ for(i = first_pde; i <= last_pde; i++) { ++ if(0 == (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & MALI_MMU_FLAGS_PRESENT)) { ++ /* Page table not present */ ++ MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); ++ MALI_DEBUG_ASSERT(NULL == pagedir->page_entries_mapped[i]); ++ ++ err = mali_mmu_get_table_page(&pde_phys, &pde_mapping); ++ if(_MALI_OSK_ERR_OK != err) { ++ MALI_PRINT_ERROR(("Failed to allocate page table page.\n")); ++ return err; ++ } ++ pagedir->page_entries_mapped[i] = pde_mapping; ++ ++ /* Update PDE, mark as present */ ++ _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), ++ pde_phys | MALI_MMU_FLAGS_PRESENT); ++ ++ MALI_DEBUG_ASSERT(0 == pagedir->page_entries_usage_count[i]); ++ pagedir->page_entries_usage_count[i] = 1; ++ } else { ++ pagedir->page_entries_usage_count[i]++; ++ } ++ } ++ _mali_osk_write_mem_barrier(); ++ ++ MALI_SUCCESS; ++} ++ ++MALI_STATIC_INLINE void mali_mmu_zero_pte(mali_io_address page_table, u32 mali_address, u32 size) ++{ ++ int i; ++ const int first_pte = MALI_MMU_PTE_ENTRY(mali_address); ++ const int last_pte = MALI_MMU_PTE_ENTRY(mali_address + size - 1); ++ ++ for (i = first_pte; i <= last_pte; i++) { ++ _mali_osk_mem_iowrite32_relaxed(page_table, i * sizeof(u32), 0); ++ } ++} ++ ++_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size) ++{ ++ const int first_pde = MALI_MMU_PDE_ENTRY(mali_address); ++ const int last_pde = MALI_MMU_PDE_ENTRY(mali_address + size - 1); ++ u32 left = size; ++ int i; ++ mali_bool pd_changed = MALI_FALSE; ++ u32 pages_to_invalidate[3]; /* hard-coded to 3: max two pages from the PT level plus max one page from PD level */ ++ u32 num_pages_inv = 0; ++ mali_bool invalidate_all = MALI_FALSE; /* safety mechanism in case page_entries_usage_count is unreliable */ ++ ++ /* For all page directory entries in range. */ ++ for (i = first_pde; i <= last_pde; i++) { ++ u32 size_in_pde, offset; ++ ++ MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[i]); ++ MALI_DEBUG_ASSERT(0 != pagedir->page_entries_usage_count[i]); ++ ++ /* Offset into page table, 0 if mali_address is 4MiB aligned */ ++ offset = (mali_address & (MALI_MMU_VIRTUAL_PAGE_SIZE - 1)); ++ if (left < MALI_MMU_VIRTUAL_PAGE_SIZE - offset) { ++ size_in_pde = left; ++ } else { ++ size_in_pde = MALI_MMU_VIRTUAL_PAGE_SIZE - offset; ++ } ++ ++ pagedir->page_entries_usage_count[i]--; ++ ++ /* If entire page table is unused, free it */ ++ if (0 == pagedir->page_entries_usage_count[i]) { ++ u32 page_phys; ++ void *page_virt; ++ MALI_DEBUG_PRINT(4, ("Releasing page table as this is the last reference\n")); ++ /* last reference removed, no need to zero out each PTE */ ++ ++ page_phys = MALI_MMU_ENTRY_ADDRESS(_mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32))); ++ page_virt = pagedir->page_entries_mapped[i]; ++ pagedir->page_entries_mapped[i] = NULL; ++ _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i*sizeof(u32), 0); ++ ++ mali_mmu_release_table_page(page_phys, page_virt); ++ pd_changed = MALI_TRUE; ++ } else { ++ MALI_DEBUG_ASSERT(num_pages_inv < 2); ++ if (num_pages_inv < 2) { ++ pages_to_invalidate[num_pages_inv] = mali_page_directory_get_phys_address(pagedir, i); ++ num_pages_inv++; ++ } else { ++ invalidate_all = MALI_TRUE; ++ } ++ ++ /* If part of the page table is still in use, zero the relevant PTEs */ ++ mali_mmu_zero_pte(pagedir->page_entries_mapped[i], mali_address, size_in_pde); ++ } ++ ++ left -= size_in_pde; ++ mali_address += size_in_pde; ++ } ++ _mali_osk_write_mem_barrier(); ++ ++ /* L2 pages invalidation */ ++ if (MALI_TRUE == pd_changed) { ++ MALI_DEBUG_ASSERT(num_pages_inv < 3); ++ if (num_pages_inv < 3) { ++ pages_to_invalidate[num_pages_inv] = pagedir->page_directory; ++ num_pages_inv++; ++ } else { ++ invalidate_all = MALI_TRUE; ++ } ++ } ++ ++ if (invalidate_all) { ++ mali_l2_cache_invalidate_all(); ++ } else { ++ mali_l2_cache_invalidate_all_pages(pages_to_invalidate, num_pages_inv); ++ } ++ ++ MALI_SUCCESS; ++} ++ ++struct mali_page_directory *mali_mmu_pagedir_alloc(void) ++{ ++ struct mali_page_directory *pagedir; ++ ++ pagedir = _mali_osk_calloc(1, sizeof(struct mali_page_directory)); ++ if(NULL == pagedir) { ++ return NULL; ++ } ++ ++ if(_MALI_OSK_ERR_OK != mali_mmu_get_table_page(&pagedir->page_directory, &pagedir->page_directory_mapped)) { ++ _mali_osk_free(pagedir); ++ return NULL; ++ } ++ ++ /* Zero page directory */ ++ fill_page(pagedir->page_directory_mapped, 0); ++ ++ return pagedir; ++} ++ ++void mali_mmu_pagedir_free(struct mali_page_directory *pagedir) ++{ ++ const int num_page_table_entries = sizeof(pagedir->page_entries_mapped) / sizeof(pagedir->page_entries_mapped[0]); ++ int i; ++ ++ /* Free referenced page tables and zero PDEs. */ ++ for (i = 0; i < num_page_table_entries; i++) { ++ if (pagedir->page_directory_mapped && (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, sizeof(u32)*i) & MALI_MMU_FLAGS_PRESENT)) { ++ u32 phys = _mali_osk_mem_ioread32(pagedir->page_directory_mapped, i*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK; ++ _mali_osk_mem_iowrite32_relaxed(pagedir->page_directory_mapped, i * sizeof(u32), 0); ++ mali_mmu_release_table_page(phys, pagedir->page_entries_mapped[i]); ++ } ++ } ++ _mali_osk_write_mem_barrier(); ++ ++ /* Free the page directory page. */ ++ mali_mmu_release_table_page(pagedir->page_directory, pagedir->page_directory_mapped); ++ ++ _mali_osk_free(pagedir); ++} ++ ++ ++void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size, u32 permission_bits) ++{ ++ u32 end_address = mali_address + size; ++ ++ /* Map physical pages into MMU page tables */ ++ for ( ; mali_address < end_address; mali_address += MALI_MMU_PAGE_SIZE, phys_address += MALI_MMU_PAGE_SIZE) { ++ MALI_DEBUG_ASSERT_POINTER(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)]); ++ _mali_osk_mem_iowrite32_relaxed(pagedir->page_entries_mapped[MALI_MMU_PDE_ENTRY(mali_address)], ++ MALI_MMU_PTE_ENTRY(mali_address) * sizeof(u32), ++ phys_address | permission_bits); ++ } ++} ++ ++u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index) ++{ ++ return (_mali_osk_mem_ioread32(pagedir->page_directory_mapped, index*sizeof(u32)) & ~MALI_MMU_FLAGS_MASK); ++} ++ ++/* For instrumented */ ++struct dump_info { ++ u32 buffer_left; ++ u32 register_writes_size; ++ u32 page_table_dump_size; ++ u32 *buffer; ++}; ++ ++static _mali_osk_errcode_t writereg(u32 where, u32 what, const char *comment, struct dump_info *info) ++{ ++ if (NULL != info) { ++ info->register_writes_size += sizeof(u32)*2; /* two 32-bit words */ ++ ++ if (NULL != info->buffer) { ++ /* check that we have enough space */ ++ if (info->buffer_left < sizeof(u32)*2) MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ ++ *info->buffer = where; ++ info->buffer++; ++ ++ *info->buffer = what; ++ info->buffer++; ++ ++ info->buffer_left -= sizeof(u32)*2; ++ } ++ } ++ ++ MALI_SUCCESS; ++} ++ ++static _mali_osk_errcode_t mali_mmu_dump_page(mali_io_address page, u32 phys_addr, struct dump_info * info) ++{ ++ if (NULL != info) { ++ /* 4096 for the page and 4 bytes for the address */ ++ const u32 page_size_in_elements = MALI_MMU_PAGE_SIZE / 4; ++ const u32 page_size_in_bytes = MALI_MMU_PAGE_SIZE; ++ const u32 dump_size_in_bytes = MALI_MMU_PAGE_SIZE + 4; ++ ++ info->page_table_dump_size += dump_size_in_bytes; ++ ++ if (NULL != info->buffer) { ++ if (info->buffer_left < dump_size_in_bytes) MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ ++ *info->buffer = phys_addr; ++ info->buffer++; ++ ++ _mali_osk_memcpy(info->buffer, page, page_size_in_bytes); ++ info->buffer += page_size_in_elements; ++ ++ info->buffer_left -= dump_size_in_bytes; ++ } ++ } ++ ++ MALI_SUCCESS; ++} ++ ++static _mali_osk_errcode_t dump_mmu_page_table(struct mali_page_directory *pagedir, struct dump_info * info) ++{ ++ MALI_DEBUG_ASSERT_POINTER(pagedir); ++ MALI_DEBUG_ASSERT_POINTER(info); ++ ++ if (NULL != pagedir->page_directory_mapped) { ++ int i; ++ ++ MALI_CHECK_NO_ERROR( ++ mali_mmu_dump_page(pagedir->page_directory_mapped, pagedir->page_directory, info) ++ ); ++ ++ for (i = 0; i < 1024; i++) { ++ if (NULL != pagedir->page_entries_mapped[i]) { ++ MALI_CHECK_NO_ERROR( ++ mali_mmu_dump_page(pagedir->page_entries_mapped[i], ++ _mali_osk_mem_ioread32(pagedir->page_directory_mapped, ++ i * sizeof(u32)) & ~MALI_MMU_FLAGS_MASK, info) ++ ); ++ } ++ } ++ } ++ ++ MALI_SUCCESS; ++} ++ ++static _mali_osk_errcode_t dump_mmu_registers(struct mali_page_directory *pagedir, struct dump_info * info) ++{ ++ MALI_CHECK_NO_ERROR(writereg(0x00000000, pagedir->page_directory, ++ "set the page directory address", info)); ++ MALI_CHECK_NO_ERROR(writereg(0x00000008, 4, "zap???", info)); ++ MALI_CHECK_NO_ERROR(writereg(0x00000008, 0, "enable paging", info)); ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ) ++{ ++ struct dump_info info = { 0, 0, 0, NULL }; ++ struct mali_session_data * session_data; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session_data = (struct mali_session_data *)(args->ctx); ++ ++ MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); ++ MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); ++ args->size = info.register_writes_size + info.page_table_dump_size; ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ) ++{ ++ struct dump_info info = { 0, 0, 0, NULL }; ++ struct mali_session_data * session_data; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ MALI_CHECK_NON_NULL(args->buffer, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session_data = (struct mali_session_data *)(args->ctx); ++ ++ info.buffer_left = args->size; ++ info.buffer = args->buffer; ++ ++ args->register_writes = info.buffer; ++ MALI_CHECK_NO_ERROR(dump_mmu_registers(session_data->page_directory, &info)); ++ ++ args->page_table_dump = info.buffer; ++ MALI_CHECK_NO_ERROR(dump_mmu_page_table(session_data->page_directory, &info)); ++ ++ args->register_writes_size = info.register_writes_size; ++ args->page_table_dump_size = info.page_table_dump_size; ++ ++ MALI_SUCCESS; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.h +new file mode 100644 +index 0000000..2d29458 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_mmu_page_directory.h +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MMU_PAGE_DIRECTORY_H__ ++#define __MALI_MMU_PAGE_DIRECTORY_H__ ++ ++#include "mali_osk.h" ++ ++/** ++ * Size of an MMU page in bytes ++ */ ++#define MALI_MMU_PAGE_SIZE 0x1000 ++ ++/* ++ * Size of the address space referenced by a page table page ++ */ ++#define MALI_MMU_VIRTUAL_PAGE_SIZE 0x400000 /* 4 MiB */ ++ ++/** ++ * Page directory index from address ++ * Calculates the page directory index from the given address ++ */ ++#define MALI_MMU_PDE_ENTRY(address) (((address)>>22) & 0x03FF) ++ ++/** ++ * Page table index from address ++ * Calculates the page table index from the given address ++ */ ++#define MALI_MMU_PTE_ENTRY(address) (((address)>>12) & 0x03FF) ++ ++/** ++ * Extract the memory address from an PDE/PTE entry ++ */ ++#define MALI_MMU_ENTRY_ADDRESS(value) ((value) & 0xFFFFFC00) ++ ++#define MALI_INVALID_PAGE ((u32)(~0)) ++ ++/** ++ * ++ */ ++typedef enum mali_mmu_entry_flags { ++ MALI_MMU_FLAGS_PRESENT = 0x01, ++ MALI_MMU_FLAGS_READ_PERMISSION = 0x02, ++ MALI_MMU_FLAGS_WRITE_PERMISSION = 0x04, ++ MALI_MMU_FLAGS_OVERRIDE_CACHE = 0x8, ++ MALI_MMU_FLAGS_WRITE_CACHEABLE = 0x10, ++ MALI_MMU_FLAGS_WRITE_ALLOCATE = 0x20, ++ MALI_MMU_FLAGS_WRITE_BUFFERABLE = 0x40, ++ MALI_MMU_FLAGS_READ_CACHEABLE = 0x80, ++ MALI_MMU_FLAGS_READ_ALLOCATE = 0x100, ++ MALI_MMU_FLAGS_MASK = 0x1FF, ++} mali_mmu_entry_flags; ++ ++ ++#define MALI_MMU_FLAGS_FORCE_GP_READ_ALLOCATE ( \ ++MALI_MMU_FLAGS_PRESENT | \ ++ MALI_MMU_FLAGS_READ_PERMISSION | \ ++ MALI_MMU_FLAGS_WRITE_PERMISSION | \ ++ MALI_MMU_FLAGS_OVERRIDE_CACHE | \ ++ MALI_MMU_FLAGS_WRITE_CACHEABLE | \ ++ MALI_MMU_FLAGS_WRITE_BUFFERABLE | \ ++ MALI_MMU_FLAGS_READ_CACHEABLE | \ ++ MALI_MMU_FLAGS_READ_ALLOCATE ) ++ ++#define MALI_MMU_FLAGS_DEFAULT ( \ ++ MALI_MMU_FLAGS_PRESENT | \ ++ MALI_MMU_FLAGS_READ_PERMISSION | \ ++ MALI_MMU_FLAGS_WRITE_PERMISSION ) ++ ++ ++struct mali_page_directory { ++ u32 page_directory; /**< Physical address of the memory session's page directory */ ++ mali_io_address page_directory_mapped; /**< Pointer to the mapped version of the page directory into the kernel's address space */ ++ ++ mali_io_address page_entries_mapped[1024]; /**< Pointers to the page tables which exists in the page directory mapped into the kernel's address space */ ++ u32 page_entries_usage_count[1024]; /**< Tracks usage count of the page table pages, so they can be releases on the last reference */ ++}; ++ ++/* Map Mali virtual address space (i.e. ensure page tables exist for the virtual range) */ ++_mali_osk_errcode_t mali_mmu_pagedir_map(struct mali_page_directory *pagedir, u32 mali_address, u32 size); ++_mali_osk_errcode_t mali_mmu_pagedir_unmap(struct mali_page_directory *pagedir, u32 mali_address, u32 size); ++ ++/* Back virtual address space with actual pages. Assumes input is contiguous and 4k aligned. */ ++void mali_mmu_pagedir_update(struct mali_page_directory *pagedir, u32 mali_address, u32 phys_address, u32 size, u32 cache_settings); ++ ++u32 mali_page_directory_get_phys_address(struct mali_page_directory *pagedir, u32 index); ++ ++u32 mali_allocate_empty_page(mali_io_address *virtual); ++void mali_free_empty_page(u32 address, mali_io_address virtual); ++_mali_osk_errcode_t mali_create_fault_flush_pages(u32 *page_directory, mali_io_address *page_directory_mapping, ++ u32 *page_table, mali_io_address *page_table_mapping, ++ u32 *data_page, mali_io_address *data_page_mapping); ++void mali_destroy_fault_flush_pages(u32 *page_directory, mali_io_address *page_directory_mapping, ++ u32 *page_table, mali_io_address *page_table_mapping, ++ u32 *data_page, mali_io_address *data_page_mapping); ++ ++struct mali_page_directory *mali_mmu_pagedir_alloc(void); ++void mali_mmu_pagedir_free(struct mali_page_directory *pagedir); ++ ++#endif /* __MALI_MMU_PAGE_DIRECTORY_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk.h +new file mode 100644 +index 0000000..5a9cf36 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk.h +@@ -0,0 +1,1335 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk.h ++ * Defines the OS abstraction layer for the kernel device driver (OSK) ++ */ ++ ++#ifndef __MALI_OSK_H__ ++#define __MALI_OSK_H__ ++ ++#include "mali_osk_types.h" ++#include "mali_osk_specific.h" /* include any per-os specifics */ ++#include "mali_osk_locks.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * @addtogroup uddapi Unified Device Driver (UDD) APIs ++ * ++ * @{ ++ */ ++ ++/** ++ * @addtogroup oskapi UDD OS Abstraction for Kernel-side (OSK) APIs ++ * ++ * @{ ++ */ ++ ++/** @addtogroup _mali_osk_lock OSK Mutual Exclusion Locks ++ * @{ */ ++ ++#ifdef DEBUG ++/** @brief Macro for asserting that the current thread holds a given lock ++ */ ++#define MALI_DEBUG_ASSERT_LOCK_HELD(l) MALI_DEBUG_ASSERT(_mali_osk_lock_get_owner((_mali_osk_lock_debug_t *)l) == _mali_osk_get_tid()); ++ ++/** @brief returns a lock's owner (thread id) if debugging is enabled ++ */ ++#else ++#define MALI_DEBUG_ASSERT_LOCK_HELD(l) do {} while(0) ++#endif ++ ++/** @} */ /* end group _mali_osk_lock */ ++ ++/** @addtogroup _mali_osk_miscellaneous ++ * @{ */ ++ ++/** @brief Find the containing structure of another structure ++ * ++ * This is the reverse of the operation 'offsetof'. This means that the ++ * following condition is satisfied: ++ * ++ * ptr == _MALI_OSK_CONTAINER_OF( &ptr->member, type, member ) ++ * ++ * When ptr is of type 'type'. ++ * ++ * Its purpose it to recover a larger structure that has wrapped a smaller one. ++ * ++ * @note no type or memory checking occurs to ensure that a wrapper structure ++ * does in fact exist, and that it is being recovered with respect to the ++ * correct member. ++ * ++ * @param ptr the pointer to the member that is contained within the larger ++ * structure ++ * @param type the type of the structure that contains the member ++ * @param member the name of the member in the structure that ptr points to. ++ * @return a pointer to a \a type object which contains \a member, as pointed ++ * to by \a ptr. ++ */ ++#define _MALI_OSK_CONTAINER_OF(ptr, type, member) \ ++ ((type *)( ((char *)ptr) - offsetof(type,member) )) ++ ++/** @addtogroup _mali_osk_wq ++ * @{ */ ++ ++/** @brief Initialize work queues (for deferred work) ++ * ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_wq_init(void); ++ ++/** @brief Terminate work queues (for deferred work) ++ */ ++void _mali_osk_wq_term(void); ++ ++/** @brief Create work in the work queue ++ * ++ * Creates a work object which can be scheduled in the work queue. When ++ * scheduled, \a handler will be called with \a data as the argument. ++ * ++ * Refer to \ref _mali_osk_wq_schedule_work() for details on how work ++ * is scheduled in the queue. ++ * ++ * The returned pointer must be freed with \ref _mali_osk_wq_delete_work() ++ * when no longer needed. ++ */ ++_mali_osk_wq_work_t *_mali_osk_wq_create_work( _mali_osk_wq_work_handler_t handler, void *data ); ++ ++/** @brief A high priority version of \a _mali_osk_wq_create_work() ++ * ++ * Creates a work object which can be scheduled in the high priority work queue. ++ * ++ * This is unfortunately needed to get low latency scheduling of the Mali cores. Normally we would ++ * schedule the next job in hw_irq or tasklet, but often we can't since we need to synchronously map ++ * and unmap shared memory when a job is connected to external fences (timelines). And this requires ++ * taking a mutex. ++ * ++ * We do signal a lot of other (low priority) work also as part of the job being finished, and if we ++ * don't set this Mali scheduling thread as high priority, we see that the CPU scheduler often runs ++ * random things instead of starting the next GPU job when the GPU is idle. So setting the gpu ++ * scheduler to high priority does give a visually more responsive system. ++ * ++ * Start the high priority work with: \a _mali_osk_wq_schedule_work_high_pri() ++ */ ++_mali_osk_wq_work_t *_mali_osk_wq_create_work_high_pri( _mali_osk_wq_work_handler_t handler, void *data ); ++ ++/** @brief Delete a work object ++ * ++ * This will flush the work queue to ensure that the work handler will not ++ * be called after deletion. ++ */ ++void _mali_osk_wq_delete_work( _mali_osk_wq_work_t *work ); ++ ++/** @brief Delete a work object ++ * ++ * This will NOT flush the work queue, so only call this if you are sure that the work handler will ++ * not be called after deletion. ++ */ ++void _mali_osk_wq_delete_work_nonflush( _mali_osk_wq_work_t *work ); ++ ++/** @brief Cause a queued, deferred call of the work handler ++ * ++ * _mali_osk_wq_schedule_work provides a mechanism for enqueuing deferred calls ++ * to the work handler. After calling \ref _mali_osk_wq_schedule_work(), the ++ * work handler will be scheduled to run at some point in the future. ++ * ++ * Typically this is called by the IRQ upper-half to defer further processing of ++ * IRQ-related work to the IRQ bottom-half handler. This is necessary for work ++ * that cannot be done in an IRQ context by the IRQ upper-half handler. Timer ++ * callbacks also use this mechanism, because they are treated as though they ++ * operate in an IRQ context. Refer to \ref _mali_osk_timer_t for more ++ * information. ++ * ++ * Code that operates in a kernel-process context (with no IRQ context ++ * restrictions) may also enqueue deferred calls to the IRQ bottom-half. The ++ * advantage over direct calling is that deferred calling allows the caller and ++ * IRQ bottom half to hold the same mutex, with a guarantee that they will not ++ * deadlock just by using this mechanism. ++ * ++ * _mali_osk_wq_schedule_work() places deferred call requests on a queue, to ++ * allow for more than one thread to make a deferred call. Therfore, if it is ++ * called 'K' times, then the IRQ bottom-half will be scheduled 'K' times too. ++ * 'K' is a number that is implementation-specific. ++ * ++ * _mali_osk_wq_schedule_work() is guaranteed to not block on: ++ * - enqueuing a deferred call request. ++ * - the completion of the work handler. ++ * ++ * This is to prevent deadlock. For example, if _mali_osk_wq_schedule_work() ++ * blocked, then it would cause a deadlock when the following two conditions ++ * hold: ++ * - The work handler callback (of type _mali_osk_wq_work_handler_t) locks ++ * a mutex ++ * - And, at the same time, the caller of _mali_osk_wq_schedule_work() also ++ * holds the same mutex ++ * ++ * @note care must be taken to not overflow the queue that ++ * _mali_osk_wq_schedule_work() operates on. Code must be structured to ++ * ensure that the number of requests made to the queue is bounded. Otherwise, ++ * work will be lost. ++ * ++ * The queue that _mali_osk_wq_schedule_work implements is a FIFO of N-writer, ++ * 1-reader type. The writers are the callers of _mali_osk_wq_schedule_work ++ * (all OSK-registered IRQ upper-half handlers in the system, watchdog timers, ++ * callers from a Kernel-process context). The reader is a single thread that ++ * handles all OSK-registered work. ++ * ++ * @param work a pointer to the _mali_osk_wq_work_t object corresponding to the ++ * work to begin processing. ++ */ ++void _mali_osk_wq_schedule_work( _mali_osk_wq_work_t *work ); ++ ++/** @brief Cause a queued, deferred call of the high priority work handler ++ * ++ * Function is the same as \a _mali_osk_wq_schedule_work() with the only ++ * difference that it runs in a high (real time) priority on the system. ++ * ++ * Should only be used as a substitue for doing the same work in interrupts. ++ * ++ * This is allowed to sleep, but the work should be small since it will block ++ * all other applications. ++*/ ++void _mali_osk_wq_schedule_work_high_pri( _mali_osk_wq_work_t *work ); ++ ++/** @brief Flush the work queue ++ * ++ * This will flush the OSK work queue, ensuring all work in the queue has ++ * completed before returning. ++ * ++ * Since this blocks on the completion of work in the work-queue, the ++ * caller of this function \b must \b not hold any mutexes that are taken by ++ * any registered work handler. To do so may cause a deadlock. ++ * ++ */ ++void _mali_osk_wq_flush(void); ++ ++/** @brief Create work in the delayed work queue ++ * ++ * Creates a work object which can be scheduled in the work queue. When ++ * scheduled, a timer will be start and the \a handler will be called with ++ * \a data as the argument when timer out ++ * ++ * Refer to \ref _mali_osk_wq_delayed_schedule_work() for details on how work ++ * is scheduled in the queue. ++ * ++ * The returned pointer must be freed with \ref _mali_osk_wq_delayed_delete_work_nonflush() ++ * when no longer needed. ++ */ ++_mali_osk_wq_delayed_work_t *_mali_osk_wq_delayed_create_work(_mali_osk_wq_work_handler_t handler, void *data); ++ ++/** @brief Delete a work object ++ * ++ * This will NOT flush the work queue, so only call this if you are sure that the work handler will ++ * not be called after deletion. ++ */ ++void _mali_osk_wq_delayed_delete_work_nonflush(_mali_osk_wq_delayed_work_t *work); ++ ++/** @brief Cancel a delayed work without waiting for it to finish ++ * ++ * Note that the \a work callback function may still be running on return from ++ * _mali_osk_wq_delayed_cancel_work_async(). ++ * ++ * @param work The delayed work to be cancelled ++ */ ++void _mali_osk_wq_delayed_cancel_work_async(_mali_osk_wq_delayed_work_t *work); ++ ++/** @brief Cancel a delayed work and wait for it to finish ++ * ++ * When this function returns, the \a work was either cancelled or it finished running. ++ * ++ * @param work The delayed work to be cancelled ++ */ ++void _mali_osk_wq_delayed_cancel_work_sync(_mali_osk_wq_delayed_work_t *work); ++ ++/** @brief Put \a work task in global workqueue after delay ++ * ++ * After waiting for a given time this puts a job in the kernel-global ++ * workqueue. ++ * ++ * If \a work was already on a queue, this function will return without doing anything ++ * ++ * @param work job to be done ++ * @param delay number of jiffies to wait or 0 for immediate execution ++ */ ++void _mali_osk_wq_delayed_schedule_work(_mali_osk_wq_delayed_work_t *work, u32 delay); ++ ++/** @} */ /* end group _mali_osk_wq */ ++ ++ ++/** @addtogroup _mali_osk_irq ++ * @{ */ ++ ++/** @brief Initialize IRQ handling for a resource ++ * ++ * Registers an interrupt handler \a uhandler for the given IRQ number \a irqnum. ++ * \a data will be passed as argument to the handler when an interrupt occurs. ++ * ++ * If \a irqnum is -1, _mali_osk_irq_init will probe for the IRQ number using ++ * the supplied \a trigger_func and \a ack_func. These functions will also ++ * receive \a data as their argument. ++ * ++ * @param irqnum The IRQ number that the resource uses, as seen by the CPU. ++ * The value -1 has a special meaning which indicates the use of probing, and ++ * trigger_func and ack_func must be non-NULL. ++ * @param uhandler The interrupt handler, corresponding to a ISR handler for ++ * the resource ++ * @param int_data resource specific data, which will be passed to uhandler ++ * @param trigger_func Optional: a function to trigger the resource's irq, to ++ * probe for the interrupt. Use NULL if irqnum != -1. ++ * @param ack_func Optional: a function to acknowledge the resource's irq, to ++ * probe for the interrupt. Use NULL if irqnum != -1. ++ * @param probe_data resource-specific data, which will be passed to ++ * (if present) trigger_func and ack_func ++ * @param description textual description of the IRQ resource. ++ * @return on success, a pointer to a _mali_osk_irq_t object, which represents ++ * the IRQ handling on this resource. NULL on failure. ++ */ ++_mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandler, void *int_data, _mali_osk_irq_trigger_t trigger_func, _mali_osk_irq_ack_t ack_func, void *probe_data, const char *description ); ++ ++/** @brief Terminate IRQ handling on a resource. ++ * ++ * This will disable the interrupt from the device, and then waits for any ++ * currently executing IRQ handlers to complete. ++ * ++ * @note If work is deferred to an IRQ bottom-half handler through ++ * \ref _mali_osk_wq_schedule_work(), be sure to flush any remaining work ++ * with \ref _mali_osk_wq_flush() or (implicitly) with \ref _mali_osk_wq_delete_work() ++ * ++ * @param irq a pointer to the _mali_osk_irq_t object corresponding to the ++ * resource whose IRQ handling is to be terminated. ++ */ ++void _mali_osk_irq_term( _mali_osk_irq_t *irq ); ++ ++/** @} */ /* end group _mali_osk_irq */ ++ ++ ++/** @addtogroup _mali_osk_atomic ++ * @{ */ ++ ++/** @brief Decrement an atomic counter ++ * ++ * @note It is an error to decrement the counter beyond -(1<<23) ++ * ++ * @param atom pointer to an atomic counter */ ++void _mali_osk_atomic_dec( _mali_osk_atomic_t *atom ); ++ ++/** @brief Decrement an atomic counter, return new value ++ * ++ * @param atom pointer to an atomic counter ++ * @return The new value, after decrement */ ++u32 _mali_osk_atomic_dec_return( _mali_osk_atomic_t *atom ); ++ ++/** @brief Increment an atomic counter ++ * ++ * @note It is an error to increment the counter beyond (1<<23)-1 ++ * ++ * @param atom pointer to an atomic counter */ ++void _mali_osk_atomic_inc( _mali_osk_atomic_t *atom ); ++ ++/** @brief Increment an atomic counter, return new value ++ * ++ * @param atom pointer to an atomic counter */ ++u32 _mali_osk_atomic_inc_return( _mali_osk_atomic_t *atom ); ++ ++/** @brief Initialize an atomic counter ++ * ++ * @note the parameter required is a u32, and so signed integers should be ++ * cast to u32. ++ * ++ * @param atom pointer to an atomic counter ++ * @param val the value to initialize the atomic counter. ++ * @return _MALI_OSK_ERR_OK on success, otherwise, a suitable ++ * _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_osk_atomic_init( _mali_osk_atomic_t *atom, u32 val ); ++ ++/** @brief Read a value from an atomic counter ++ * ++ * This can only be safely used to determine the value of the counter when it ++ * is guaranteed that other threads will not be modifying the counter. This ++ * makes its usefulness limited. ++ * ++ * @param atom pointer to an atomic counter ++ */ ++u32 _mali_osk_atomic_read( _mali_osk_atomic_t *atom ); ++ ++/** @brief Terminate an atomic counter ++ * ++ * @param atom pointer to an atomic counter ++ */ ++void _mali_osk_atomic_term( _mali_osk_atomic_t *atom ); ++ ++/** @brief Assign a new val to atomic counter, and return the old atomic counter ++ * ++ * @param atom pointer to an atomic counter ++ * @param val the new value assign to the atomic counter ++ * @return the old value of the atomic counter ++ */ ++u32 _mali_osk_atomic_xchg( _mali_osk_atomic_t *atom, u32 val ); ++/** @} */ /* end group _mali_osk_atomic */ ++ ++ ++/** @defgroup _mali_osk_memory OSK Memory Allocation ++ * @{ */ ++ ++/** @brief Allocate zero-initialized memory. ++ * ++ * Returns a buffer capable of containing at least \a n elements of \a size ++ * bytes each. The buffer is initialized to zero. ++ * ++ * If there is a need for a bigger block of memory (16KB or bigger), then ++ * consider to use _mali_osk_vmalloc() instead, as this function might ++ * map down to a OS function with size limitations. ++ * ++ * The buffer is suitably aligned for storage and subsequent access of every ++ * type that the compiler supports. Therefore, the pointer to the start of the ++ * buffer may be cast into any pointer type, and be subsequently accessed from ++ * such a pointer, without loss of information. ++ * ++ * When the buffer is no longer in use, it must be freed with _mali_osk_free(). ++ * Failure to do so will cause a memory leak. ++ * ++ * @note Most toolchains supply memory allocation functions that meet the ++ * compiler's alignment requirements. ++ * ++ * @param n Number of elements to allocate ++ * @param size Size of each element ++ * @return On success, the zero-initialized buffer allocated. NULL on failure ++ */ ++void *_mali_osk_calloc( u32 n, u32 size ); ++ ++/** @brief Allocate memory. ++ * ++ * Returns a buffer capable of containing at least \a size bytes. The ++ * contents of the buffer are undefined. ++ * ++ * If there is a need for a bigger block of memory (16KB or bigger), then ++ * consider to use _mali_osk_vmalloc() instead, as this function might ++ * map down to a OS function with size limitations. ++ * ++ * The buffer is suitably aligned for storage and subsequent access of every ++ * type that the compiler supports. Therefore, the pointer to the start of the ++ * buffer may be cast into any pointer type, and be subsequently accessed from ++ * such a pointer, without loss of information. ++ * ++ * When the buffer is no longer in use, it must be freed with _mali_osk_free(). ++ * Failure to do so will cause a memory leak. ++ * ++ * @note Most toolchains supply memory allocation functions that meet the ++ * compiler's alignment requirements. ++ * ++ * Remember to free memory using _mali_osk_free(). ++ * @param size Number of bytes to allocate ++ * @return On success, the buffer allocated. NULL on failure. ++ */ ++void *_mali_osk_malloc( u32 size ); ++ ++/** @brief Free memory. ++ * ++ * Reclaims the buffer pointed to by the parameter \a ptr for the system. ++ * All memory returned from _mali_osk_malloc() and _mali_osk_calloc() ++ * must be freed before the application exits. Otherwise, ++ * a memory leak will occur. ++ * ++ * Memory must be freed once. It is an error to free the same non-NULL pointer ++ * more than once. ++ * ++ * It is legal to free the NULL pointer. ++ * ++ * @param ptr Pointer to buffer to free ++ */ ++void _mali_osk_free( void *ptr ); ++ ++/** @brief Allocate memory. ++ * ++ * Returns a buffer capable of containing at least \a size bytes. The ++ * contents of the buffer are undefined. ++ * ++ * This function is potentially slower than _mali_osk_malloc() and _mali_osk_calloc(), ++ * but do support bigger sizes. ++ * ++ * The buffer is suitably aligned for storage and subsequent access of every ++ * type that the compiler supports. Therefore, the pointer to the start of the ++ * buffer may be cast into any pointer type, and be subsequently accessed from ++ * such a pointer, without loss of information. ++ * ++ * When the buffer is no longer in use, it must be freed with _mali_osk_free(). ++ * Failure to do so will cause a memory leak. ++ * ++ * @note Most toolchains supply memory allocation functions that meet the ++ * compiler's alignment requirements. ++ * ++ * Remember to free memory using _mali_osk_free(). ++ * @param size Number of bytes to allocate ++ * @return On success, the buffer allocated. NULL on failure. ++ */ ++void *_mali_osk_valloc( u32 size ); ++ ++/** @brief Free memory. ++ * ++ * Reclaims the buffer pointed to by the parameter \a ptr for the system. ++ * All memory returned from _mali_osk_valloc() must be freed before the ++ * application exits. Otherwise a memory leak will occur. ++ * ++ * Memory must be freed once. It is an error to free the same non-NULL pointer ++ * more than once. ++ * ++ * It is legal to free the NULL pointer. ++ * ++ * @param ptr Pointer to buffer to free ++ */ ++void _mali_osk_vfree( void *ptr ); ++ ++/** @brief Copies memory. ++ * ++ * Copies the \a len bytes from the buffer pointed by the parameter \a src ++ * directly to the buffer pointed by \a dst. ++ * ++ * It is an error for \a src to overlap \a dst anywhere in \a len bytes. ++ * ++ * @param dst Pointer to the destination array where the content is to be ++ * copied. ++ * @param src Pointer to the source of data to be copied. ++ * @param len Number of bytes to copy. ++ * @return \a dst is always passed through unmodified. ++ */ ++void *_mali_osk_memcpy( void *dst, const void *src, u32 len ); ++ ++/** @brief Fills memory. ++ * ++ * Sets the first \a n bytes of the block of memory pointed to by \a s to ++ * the specified value ++ * @param s Pointer to the block of memory to fill. ++ * @param c Value to be set, passed as u32. Only the 8 Least Significant Bits (LSB) ++ * are used. ++ * @param n Number of bytes to be set to the value. ++ * @return \a s is always passed through unmodified ++ */ ++void *_mali_osk_memset( void *s, u32 c, u32 n ); ++/** @} */ /* end group _mali_osk_memory */ ++ ++ ++/** @brief Checks the amount of memory allocated ++ * ++ * Checks that not more than \a max_allocated bytes are allocated. ++ * ++ * Some OS bring up an interactive out of memory dialogue when the ++ * system runs out of memory. This can stall non-interactive ++ * apps (e.g. automated test runs). This function can be used to ++ * not trigger the OOM dialogue by keeping allocations ++ * within a certain limit. ++ * ++ * @return MALI_TRUE when \a max_allocated bytes are not in use yet. MALI_FALSE ++ * when at least \a max_allocated bytes are in use. ++ */ ++mali_bool _mali_osk_mem_check_allocated( u32 max_allocated ); ++ ++ ++/** @addtogroup _mali_osk_low_level_memory ++ * @{ */ ++ ++/** @brief Issue a memory barrier ++ * ++ * This defines an arbitrary memory barrier operation, which forces an ordering constraint ++ * on memory read and write operations. ++ */ ++void _mali_osk_mem_barrier( void ); ++ ++/** @brief Issue a write memory barrier ++ * ++ * This defines an write memory barrier operation which forces an ordering constraint ++ * on memory write operations. ++ */ ++void _mali_osk_write_mem_barrier( void ); ++ ++/** @brief Map a physically contiguous region into kernel space ++ * ++ * This is primarily used for mapping in registers from resources, and Mali-MMU ++ * page tables. The mapping is only visable from kernel-space. ++ * ++ * Access has to go through _mali_osk_mem_ioread32 and _mali_osk_mem_iowrite32 ++ * ++ * @param phys CPU-physical base address of the memory to map in. This must ++ * be aligned to the system's page size, which is assumed to be 4K. ++ * @param size the number of bytes of physically contiguous address space to ++ * map in ++ * @param description A textual description of the memory being mapped in. ++ * @return On success, a Mali IO address through which the mapped-in ++ * memory/registers can be accessed. NULL on failure. ++ */ ++mali_io_address _mali_osk_mem_mapioregion( u32 phys, u32 size, const char *description ); ++ ++/** @brief Unmap a physically contiguous address range from kernel space. ++ * ++ * The address range should be one previously mapped in through ++ * _mali_osk_mem_mapioregion. ++ * ++ * It is a programming error to do (but not limited to) the following: ++ * - attempt an unmap twice ++ * - unmap only part of a range obtained through _mali_osk_mem_mapioregion ++ * - unmap more than the range obtained through _mali_osk_mem_mapioregion ++ * - unmap an address range that was not successfully mapped using ++ * _mali_osk_mem_mapioregion ++ * - provide a mapping that does not map to phys. ++ * ++ * @param phys CPU-physical base address of the memory that was originally ++ * mapped in. This must be aligned to the system's page size, which is assumed ++ * to be 4K ++ * @param size The number of bytes that were originally mapped in. ++ * @param mapping The Mali IO address through which the mapping is ++ * accessed. ++ */ ++void _mali_osk_mem_unmapioregion( u32 phys, u32 size, mali_io_address mapping ); ++ ++/** @brief Allocate and Map a physically contiguous region into kernel space ++ * ++ * This is used for allocating physically contiguous regions (such as Mali-MMU ++ * page tables) and mapping them into kernel space. The mapping is only ++ * visible from kernel-space. ++ * ++ * The alignment of the returned memory is guaranteed to be at least ++ * _MALI_OSK_CPU_PAGE_SIZE. ++ * ++ * Access must go through _mali_osk_mem_ioread32 and _mali_osk_mem_iowrite32 ++ * ++ * @note This function is primarily to provide support for OSs that are ++ * incapable of separating the tasks 'allocate physically contiguous memory' ++ * and 'map it into kernel space' ++ * ++ * @param[out] phys CPU-physical base address of memory that was allocated. ++ * (*phys) will be guaranteed to be aligned to at least ++ * _MALI_OSK_CPU_PAGE_SIZE on success. ++ * ++ * @param[in] size the number of bytes of physically contiguous memory to ++ * allocate. This must be a multiple of _MALI_OSK_CPU_PAGE_SIZE. ++ * ++ * @return On success, a Mali IO address through which the mapped-in ++ * memory/registers can be accessed. NULL on failure, and (*phys) is unmodified. ++ */ ++mali_io_address _mali_osk_mem_allocioregion( u32 *phys, u32 size ); ++ ++/** @brief Free a physically contiguous address range from kernel space. ++ * ++ * The address range should be one previously mapped in through ++ * _mali_osk_mem_allocioregion. ++ * ++ * It is a programming error to do (but not limited to) the following: ++ * - attempt a free twice on the same ioregion ++ * - free only part of a range obtained through _mali_osk_mem_allocioregion ++ * - free more than the range obtained through _mali_osk_mem_allocioregion ++ * - free an address range that was not successfully mapped using ++ * _mali_osk_mem_allocioregion ++ * - provide a mapping that does not map to phys. ++ * ++ * @param phys CPU-physical base address of the memory that was originally ++ * mapped in, which was aligned to _MALI_OSK_CPU_PAGE_SIZE. ++ * @param size The number of bytes that were originally mapped in, which was ++ * a multiple of _MALI_OSK_CPU_PAGE_SIZE. ++ * @param mapping The Mali IO address through which the mapping is ++ * accessed. ++ */ ++void _mali_osk_mem_freeioregion( u32 phys, u32 size, mali_io_address mapping ); ++ ++/** @brief Request a region of physically contiguous memory ++ * ++ * This is used to ensure exclusive access to a region of physically contigous ++ * memory. ++ * ++ * It is acceptable to implement this as a stub. However, it is then the job ++ * of the System Integrator to ensure that no other device driver will be using ++ * the physical address ranges used by Mali, while the Mali device driver is ++ * loaded. ++ * ++ * @param phys CPU-physical base address of the memory to request. This must ++ * be aligned to the system's page size, which is assumed to be 4K. ++ * @param size the number of bytes of physically contiguous address space to ++ * request. ++ * @param description A textual description of the memory being requested. ++ * @return _MALI_OSK_ERR_OK on success. Otherwise, a suitable ++ * _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_osk_mem_reqregion( u32 phys, u32 size, const char *description ); ++ ++/** @brief Un-request a region of physically contiguous memory ++ * ++ * This is used to release a regious of physically contiguous memory previously ++ * requested through _mali_osk_mem_reqregion, so that other device drivers may ++ * use it. This will be called at time of Mali device driver termination. ++ * ++ * It is a programming error to attempt to: ++ * - unrequest a region twice ++ * - unrequest only part of a range obtained through _mali_osk_mem_reqregion ++ * - unrequest more than the range obtained through _mali_osk_mem_reqregion ++ * - unrequest an address range that was not successfully requested using ++ * _mali_osk_mem_reqregion ++ * ++ * @param phys CPU-physical base address of the memory to un-request. This must ++ * be aligned to the system's page size, which is assumed to be 4K ++ * @param size the number of bytes of physically contiguous address space to ++ * un-request. ++ */ ++void _mali_osk_mem_unreqregion( u32 phys, u32 size ); ++ ++/** @brief Read from a location currently mapped in through ++ * _mali_osk_mem_mapioregion ++ * ++ * This reads a 32-bit word from a 32-bit aligned location. It is a programming ++ * error to provide unaligned locations, or to read from memory that is not ++ * mapped in, or not mapped through either _mali_osk_mem_mapioregion() or ++ * _mali_osk_mem_allocioregion(). ++ * ++ * @param mapping Mali IO address to read from ++ * @param offset Byte offset from the given IO address to operate on, must be a multiple of 4 ++ * @return the 32-bit word from the specified location. ++ */ ++u32 _mali_osk_mem_ioread32( volatile mali_io_address mapping, u32 offset ); ++ ++/** @brief Write to a location currently mapped in through ++ * _mali_osk_mem_mapioregion without memory barriers ++ * ++ * This write a 32-bit word to a 32-bit aligned location without using memory barrier. ++ * It is a programming error to provide unaligned locations, or to write to memory that is not ++ * mapped in, or not mapped through either _mali_osk_mem_mapioregion() or ++ * _mali_osk_mem_allocioregion(). ++ * ++ * @param mapping Mali IO address to write to ++ * @param offset Byte offset from the given IO address to operate on, must be a multiple of 4 ++ * @param val the 32-bit word to write. ++ */ ++void _mali_osk_mem_iowrite32_relaxed( volatile mali_io_address addr, u32 offset, u32 val ); ++ ++/** @brief Write to a location currently mapped in through ++ * _mali_osk_mem_mapioregion with write memory barrier ++ * ++ * This write a 32-bit word to a 32-bit aligned location. It is a programming ++ * error to provide unaligned locations, or to write to memory that is not ++ * mapped in, or not mapped through either _mali_osk_mem_mapioregion() or ++ * _mali_osk_mem_allocioregion(). ++ * ++ * @param mapping Mali IO address to write to ++ * @param offset Byte offset from the given IO address to operate on, must be a multiple of 4 ++ * @param val the 32-bit word to write. ++ */ ++void _mali_osk_mem_iowrite32( volatile mali_io_address mapping, u32 offset, u32 val ); ++ ++/** @brief Flush all CPU caches ++ * ++ * This should only be implemented if flushing of the cache is required for ++ * memory mapped in through _mali_osk_mem_mapregion. ++ */ ++void _mali_osk_cache_flushall( void ); ++ ++/** @brief Flush any caches necessary for the CPU and MALI to have the same view of a range of uncached mapped memory ++ * ++ * This should only be implemented if your OS doesn't do a full cache flush (inner & outer) ++ * after allocating uncached mapped memory. ++ * ++ * Some OS do not perform a full cache flush (including all outer caches) for uncached mapped memory. ++ * They zero the memory through a cached mapping, then flush the inner caches but not the outer caches. ++ * This is required for MALI to have the correct view of the memory. ++ */ ++void _mali_osk_cache_ensure_uncached_range_flushed( void *uncached_mapping, u32 offset, u32 size ); ++ ++/** @} */ /* end group _mali_osk_low_level_memory */ ++ ++ ++/** @addtogroup _mali_osk_notification ++ * ++ * User space notification framework ++ * ++ * Communication with user space of asynchronous events is performed through a ++ * synchronous call to the \ref u_k_api. ++ * ++ * Since the events are asynchronous, the events have to be queued until a ++ * synchronous U/K API call can be made by user-space. A U/K API call might also ++ * be received before any event has happened. Therefore the notifications the ++ * different subsystems wants to send to user space has to be queued for later ++ * reception, or a U/K API call has to be blocked until an event has occured. ++ * ++ * Typical uses of notifications are after running of jobs on the hardware or ++ * when changes to the system is detected that needs to be relayed to user ++ * space. ++ * ++ * After an event has occured user space has to be notified using some kind of ++ * message. The notification framework supports sending messages to waiting ++ * threads or queueing of messages until a U/K API call is made. ++ * ++ * The notification queue is a FIFO. There are no restrictions on the numbers ++ * of readers or writers in the queue. ++ * ++ * A message contains what user space needs to identifiy how to handle an ++ * event. This includes a type field and a possible type specific payload. ++ * ++ * A notification to user space is represented by a ++ * \ref _mali_osk_notification_t object. A sender gets hold of such an object ++ * using _mali_osk_notification_create(). The buffer given by the ++ * _mali_osk_notification_t::result_buffer field in the object is used to store ++ * any type specific data. The other fields are internal to the queue system ++ * and should not be touched. ++ * ++ * @{ */ ++ ++/** @brief Create a notification object ++ * ++ * Returns a notification object which can be added to the queue of ++ * notifications pending for user space transfer. ++ * ++ * The implementation will initialize all members of the ++ * \ref _mali_osk_notification_t object. In particular, the ++ * _mali_osk_notification_t::result_buffer member will be initialized to point ++ * to \a size bytes of storage, and that storage will be suitably aligned for ++ * storage of any structure. That is, the created buffer meets the same ++ * requirements as _mali_osk_malloc(). ++ * ++ * The notification object must be deleted when not in use. Use ++ * _mali_osk_notification_delete() for deleting it. ++ * ++ * @note You \b must \b not call _mali_osk_free() on a \ref _mali_osk_notification_t, ++ * object, or on a _mali_osk_notification_t::result_buffer. You must only use ++ * _mali_osk_notification_delete() to free the resources assocaited with a ++ * \ref _mali_osk_notification_t object. ++ * ++ * @param type The notification type ++ * @param size The size of the type specific buffer to send ++ * @return Pointer to a notification object with a suitable buffer, or NULL on error. ++ */ ++_mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size ); ++ ++/** @brief Delete a notification object ++ * ++ * This must be called to reclaim the resources of a notification object. This ++ * includes: ++ * - The _mali_osk_notification_t::result_buffer ++ * - The \ref _mali_osk_notification_t itself. ++ * ++ * A notification object \b must \b not be used after it has been deleted by ++ * _mali_osk_notification_delete(). ++ * ++ * In addition, the notification object may not be deleted while it is in a ++ * queue. That is, if it has been placed on a queue with ++ * _mali_osk_notification_queue_send(), then it must not be deleted until ++ * it has been received by a call to _mali_osk_notification_queue_receive(). ++ * Otherwise, the queue may be corrupted. ++ * ++ * @param object the notification object to delete. ++ */ ++void _mali_osk_notification_delete( _mali_osk_notification_t *object ); ++ ++/** @brief Create a notification queue ++ * ++ * Creates a notification queue which can be used to queue messages for user ++ * delivery and get queued messages from ++ * ++ * The queue is a FIFO, and has no restrictions on the numbers of readers or ++ * writers. ++ * ++ * When the queue is no longer in use, it must be terminated with ++ * \ref _mali_osk_notification_queue_term(). Failure to do so will result in a ++ * memory leak. ++ * ++ * @return Pointer to a new notification queue or NULL on error. ++ */ ++_mali_osk_notification_queue_t *_mali_osk_notification_queue_init( void ); ++ ++/** @brief Destroy a notification queue ++ * ++ * Destroys a notification queue and frees associated resources from the queue. ++ * ++ * A notification queue \b must \b not be destroyed in the following cases: ++ * - while there are \ref _mali_osk_notification_t objects in the queue. ++ * - while there are writers currently acting upon the queue. That is, while ++ * a thread is currently calling \ref _mali_osk_notification_queue_send() on ++ * the queue, or while a thread may call ++ * \ref _mali_osk_notification_queue_send() on the queue in the future. ++ * - while there are readers currently waiting upon the queue. That is, while ++ * a thread is currently calling \ref _mali_osk_notification_queue_receive() on ++ * the queue, or while a thread may call ++ * \ref _mali_osk_notification_queue_receive() on the queue in the future. ++ * ++ * Therefore, all \ref _mali_osk_notification_t objects must be flushed and ++ * deleted by the code that makes use of the notification queues, since only ++ * they know the structure of the _mali_osk_notification_t::result_buffer ++ * (even if it may only be a flat sturcture). ++ * ++ * @note Since the queue is a FIFO, the code using notification queues may ++ * create its own 'flush' type of notification, to assist in flushing the ++ * queue. ++ * ++ * Once the queue has been destroyed, it must not be used again. ++ * ++ * @param queue The queue to destroy ++ */ ++void _mali_osk_notification_queue_term( _mali_osk_notification_queue_t *queue ); ++ ++/** @brief Schedule notification for delivery ++ * ++ * When a \ref _mali_osk_notification_t object has been created successfully ++ * and set up, it may be added to the queue of objects waiting for user space ++ * transfer. ++ * ++ * The sending will not block if the queue is full. ++ * ++ * A \ref _mali_osk_notification_t object \b must \b not be put on two different ++ * queues at the same time, or enqueued twice onto a single queue before ++ * reception. However, it is acceptable for it to be requeued \em after reception ++ * from a call to _mali_osk_notification_queue_receive(), even onto the same queue. ++ * ++ * Again, requeuing must also not enqueue onto two different queues at the same ++ * time, or enqueue onto the same queue twice before reception. ++ * ++ * @param queue The notification queue to add this notification to ++ * @param object The entry to add ++ */ ++void _mali_osk_notification_queue_send( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object ); ++ ++/** @brief Receive a notification from a queue ++ * ++ * Receives a single notification from the given queue. ++ * ++ * If no notifciations are ready the thread will sleep until one becomes ready. ++ * Therefore, notifications may not be received into an ++ * IRQ or 'atomic' context (that is, a context where sleeping is disallowed). ++ * ++ * @param queue The queue to receive from ++ * @param result Pointer to storage of a pointer of type ++ * \ref _mali_osk_notification_t*. \a result will be written to such that the ++ * expression \a (*result) will evaluate to a pointer to a valid ++ * \ref _mali_osk_notification_t object, or NULL if none were received. ++ * @return _MALI_OSK_ERR_OK on success. _MALI_OSK_ERR_RESTARTSYSCALL if the sleep was interrupted. ++ */ ++_mali_osk_errcode_t _mali_osk_notification_queue_receive( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result ); ++ ++/** @brief Dequeues a notification from a queue ++ * ++ * Receives a single notification from the given queue. ++ * ++ * If no notifciations are ready the function call will return an error code. ++ * ++ * @param queue The queue to receive from ++ * @param result Pointer to storage of a pointer of type ++ * \ref _mali_osk_notification_t*. \a result will be written to such that the ++ * expression \a (*result) will evaluate to a pointer to a valid ++ * \ref _mali_osk_notification_t object, or NULL if none were received. ++ * @return _MALI_OSK_ERR_OK on success, _MALI_OSK_ERR_ITEM_NOT_FOUND if queue was empty. ++ */ ++_mali_osk_errcode_t _mali_osk_notification_queue_dequeue( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result ); ++ ++/** @} */ /* end group _mali_osk_notification */ ++ ++ ++/** @addtogroup _mali_osk_timer ++ * ++ * Timers use the OS's representation of time, which are 'ticks'. This is to ++ * prevent aliasing problems between the internal timer time, and the time ++ * asked for. ++ * ++ * @{ */ ++ ++/** @brief Initialize a timer ++ * ++ * Allocates resources for a new timer, and initializes them. This does not ++ * start the timer. ++ * ++ * @return a pointer to the allocated timer object, or NULL on failure. ++ */ ++_mali_osk_timer_t *_mali_osk_timer_init(void); ++ ++/** @brief Start a timer ++ * ++ * It is an error to start a timer without setting the callback via ++ * _mali_osk_timer_setcallback(). ++ * ++ * It is an error to use this to start an already started timer. ++ * ++ * The timer will expire in \a ticks_to_expire ticks, at which point, the ++ * callback function will be invoked with the callback-specific data, ++ * as registered by _mali_osk_timer_setcallback(). ++ * ++ * @param tim the timer to start ++ * @param ticks_to_expire the amount of time in ticks for the timer to run ++ * before triggering. ++ */ ++void _mali_osk_timer_add( _mali_osk_timer_t *tim, u32 ticks_to_expire ); ++ ++/** @brief Modify a timer ++ * ++ * Set the relative time at which a timer will expire, and start it if it is ++ * stopped. If \a ticks_to_expire 0 the timer fires immediately. ++ * ++ * It is an error to modify a timer without setting the callback via ++ * _mali_osk_timer_setcallback(). ++ * ++ * The timer will expire at \a ticks_to_expire from the time of the call, at ++ * which point, the callback function will be invoked with the ++ * callback-specific data, as set by _mali_osk_timer_setcallback(). ++ * ++ * @param tim the timer to modify, and start if necessary ++ * @param ticks_to_expire the \em absolute time in ticks at which this timer ++ * should trigger. ++ * ++ */ ++void _mali_osk_timer_mod( _mali_osk_timer_t *tim, u32 ticks_to_expire); ++ ++/** @brief Stop a timer, and block on its completion. ++ * ++ * Stop the timer. When the function returns, it is guaranteed that the timer's ++ * callback will not be running on any CPU core. ++ * ++ * Since stoping the timer blocks on compeletion of the callback, the callback ++ * may not obtain any mutexes that the caller holds. Otherwise, a deadlock will ++ * occur. ++ * ++ * @note While the callback itself is guaranteed to not be running, work ++ * enqueued on the work-queue by the timer (with ++ * \ref _mali_osk_wq_schedule_work()) may still run. The timer callback and ++ * work handler must take this into account. ++ * ++ * It is legal to stop an already stopped timer. ++ * ++ * @param tim the timer to stop. ++ * ++ */ ++void _mali_osk_timer_del( _mali_osk_timer_t *tim ); ++ ++/** @brief Stop a timer. ++ * ++ * Stop the timer. When the function returns, the timer's callback may still be ++ * running on any CPU core. ++ * ++ * It is legal to stop an already stopped timer. ++ * ++ * @param tim the timer to stop. ++ */ ++void _mali_osk_timer_del_async( _mali_osk_timer_t *tim ); ++ ++/** @brief Check if timer is pending. ++ * ++ * Check if timer is active. ++ * ++ * @param tim the timer to check ++ * @return MALI_TRUE if time is active, MALI_FALSE if it is not active ++ */ ++mali_bool _mali_osk_timer_pending( _mali_osk_timer_t *tim); ++ ++/** @brief Set a timer's callback parameters. ++ * ++ * This must be called at least once before a timer is started/modified. ++ * ++ * After a timer has been stopped or expires, the callback remains set. This ++ * means that restarting the timer will call the same function with the same ++ * parameters on expiry. ++ * ++ * @param tim the timer to set callback on. ++ * @param callback Function to call when timer expires ++ * @param data Function-specific data to supply to the function on expiry. ++ */ ++void _mali_osk_timer_setcallback( _mali_osk_timer_t *tim, _mali_osk_timer_callback_t callback, void *data ); ++ ++/** @brief Terminate a timer, and deallocate resources. ++ * ++ * The timer must first be stopped by calling _mali_osk_timer_del(). ++ * ++ * It is a programming error for _mali_osk_timer_term() to be called on: ++ * - timer that is currently running ++ * - a timer that is currently executing its callback. ++ * ++ * @param tim the timer to deallocate. ++ */ ++void _mali_osk_timer_term( _mali_osk_timer_t *tim ); ++/** @} */ /* end group _mali_osk_timer */ ++ ++ ++/** @defgroup _mali_osk_time OSK Time functions ++ * ++ * \ref _mali_osk_time use the OS's representation of time, which are ++ * 'ticks'. This is to prevent aliasing problems between the internal timer ++ * time, and the time asked for. ++ * ++ * OS tick time is measured as a u32. The time stored in a u32 may either be ++ * an absolute time, or a time delta between two events. Whilst it is valid to ++ * use math opeartors to \em change the tick value represented as a u32, it ++ * is often only meaningful to do such operations on time deltas, rather than ++ * on absolute time. However, it is meaningful to add/subtract time deltas to ++ * absolute times. ++ * ++ * Conversion between tick time and milliseconds (ms) may not be loss-less, ++ * and are \em implementation \em depenedant. ++ * ++ * Code use OS time must take this into account, since: ++ * - a small OS time may (or may not) be rounded ++ * - a large time may (or may not) overflow ++ * ++ * @{ */ ++ ++/** @brief Return whether ticka occurs after tickb ++ * ++ * Some OSs handle tick 'rollover' specially, and so can be more robust against ++ * tick counters rolling-over. This function must therefore be called to ++ * determine if a time (in ticks) really occurs after another time (in ticks). ++ * ++ * @param ticka ticka ++ * @param tickb tickb ++ * @return non-zero if ticka represents a time that occurs after tickb. ++ * Zero otherwise. ++ */ ++int _mali_osk_time_after( u32 ticka, u32 tickb ); ++ ++/** @brief Convert milliseconds to OS 'ticks' ++ * ++ * @param ms time interval in milliseconds ++ * @return the corresponding time interval in OS ticks. ++ */ ++u32 _mali_osk_time_mstoticks( u32 ms ); ++ ++/** @brief Convert OS 'ticks' to milliseconds ++ * ++ * @param ticks time interval in OS ticks. ++ * @return the corresponding time interval in milliseconds ++ */ ++u32 _mali_osk_time_tickstoms( u32 ticks ); ++ ++ ++/** @brief Get the current time in OS 'ticks'. ++ * @return the current time in OS 'ticks'. ++ */ ++u32 _mali_osk_time_tickcount( void ); ++ ++/** @brief Cause a microsecond delay ++ * ++ * The delay will have microsecond resolution, and is necessary for correct ++ * operation of the driver. At worst, the delay will be \b at least \a usecs ++ * microseconds, and so may be (significantly) more. ++ * ++ * This function may be implemented as a busy-wait, which is the most sensible ++ * implementation. On OSs where there are situations in which a thread must not ++ * sleep, this is definitely implemented as a busy-wait. ++ * ++ * @param usecs the number of microseconds to wait for. ++ */ ++void _mali_osk_time_ubusydelay( u32 usecs ); ++ ++/** @brief Return time in nano seconds, since any given reference. ++ * ++ * @return Time in nano seconds ++ */ ++u64 _mali_osk_time_get_ns( void ); ++ ++ ++/** @} */ /* end group _mali_osk_time */ ++ ++/** @defgroup _mali_osk_math OSK Math ++ * @{ */ ++ ++/** @brief Count Leading Zeros (Little-endian) ++ * ++ * @note This function must be implemented to support the reference ++ * implementation of _mali_osk_find_first_zero_bit, as defined in ++ * mali_osk_bitops.h. ++ * ++ * @param val 32-bit words to count leading zeros on ++ * @return the number of leading zeros. ++ */ ++u32 _mali_osk_clz( u32 val ); ++ ++/** @brief find last (most-significant) bit set ++ * ++ * @param val 32-bit words to count last bit set on ++ * @return last bit set. ++ */ ++u32 _mali_osk_fls( u32 val ); ++ ++/** @} */ /* end group _mali_osk_math */ ++ ++/** @addtogroup _mali_osk_wait_queue OSK Wait Queue functionality ++ * @{ */ ++ ++/** @brief Initialize an empty Wait Queue */ ++_mali_osk_wait_queue_t* _mali_osk_wait_queue_init( void ); ++ ++/** @brief Sleep if condition is false ++ * ++ * @param queue the queue to use ++ * @param condition function pointer to a boolean function ++ * @param data data parameter for condition function ++ * ++ * Put thread to sleep if the given \a condition function returns false. When ++ * being asked to wake up again, the condition will be re-checked and the ++ * thread only woken up if the condition is now true. ++ */ ++void _mali_osk_wait_queue_wait_event( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void *), void *data ); ++ ++/** @brief Sleep if condition is false ++ * ++ * @param queue the queue to use ++ * @param condition function pointer to a boolean function ++ * @param data data parameter for condition function ++ * @param timeout timeout in ms ++ * ++ * Put thread to sleep if the given \a condition function returns false. When ++ * being asked to wake up again, the condition will be re-checked and the ++ * thread only woken up if the condition is now true. Will return if time ++ * exceeds timeout. ++ */ ++void _mali_osk_wait_queue_wait_event_timeout( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void *), void *data, u32 timeout ); ++ ++/** @brief Wake up all threads in wait queue if their respective conditions are ++ * true ++ * ++ * @param queue the queue whose threads should be woken up ++ * ++ * Wake up all threads in wait queue \a queue whose condition is now true. ++ */ ++void _mali_osk_wait_queue_wake_up( _mali_osk_wait_queue_t *queue ); ++ ++/** @brief terminate a wait queue ++ * ++ * @param queue the queue to terminate. ++ */ ++void _mali_osk_wait_queue_term( _mali_osk_wait_queue_t *queue ); ++/** @} */ /* end group _mali_osk_wait_queue */ ++ ++ ++/** @addtogroup _mali_osk_miscellaneous ++ * @{ */ ++ ++/** @brief Output a device driver debug message. ++ * ++ * The interpretation of \a fmt is the same as the \c format parameter in ++ * _mali_osu_vsnprintf(). ++ * ++ * @param fmt a _mali_osu_vsnprintf() style format string ++ * @param ... a variable-number of parameters suitable for \a fmt ++ */ ++void _mali_osk_dbgmsg( const char *fmt, ... ); ++ ++/** @brief Print fmt into buf. ++ * ++ * The interpretation of \a fmt is the same as the \c format parameter in ++ * _mali_osu_vsnprintf(). ++ * ++ * @param buf a pointer to the result buffer ++ * @param size the total number of bytes allowed to write to \a buf ++ * @param fmt a _mali_osu_vsnprintf() style format string ++ * @param ... a variable-number of parameters suitable for \a fmt ++ * @return The number of bytes written to \a buf ++ */ ++u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ); ++ ++/** @brief Abnormal process abort. ++ * ++ * Terminates the caller-process if this function is called. ++ * ++ * This function will be called from Debug assert-macros in mali_kernel_common.h. ++ * ++ * This function will never return - because to continue from a Debug assert ++ * could cause even more problems, and hinder debugging of the initial problem. ++ * ++ * This function is only used in Debug builds, and is not used in Release builds. ++ */ ++void _mali_osk_abort(void); ++ ++/** @brief Sets breakpoint at point where function is called. ++ * ++ * This function will be called from Debug assert-macros in mali_kernel_common.h, ++ * to assist in debugging. If debugging at this level is not required, then this ++ * function may be implemented as a stub. ++ * ++ * This function is only used in Debug builds, and is not used in Release builds. ++ */ ++void _mali_osk_break(void); ++ ++/** @brief Return an identificator for calling process. ++ * ++ * @return Identificator for calling process. ++ */ ++u32 _mali_osk_get_pid(void); ++ ++/** @brief Return an identificator for calling thread. ++ * ++ * @return Identificator for calling thread. ++ */ ++u32 _mali_osk_get_tid(void); ++ ++/** @brief Enable OS controlled runtime power management ++ */ ++void _mali_osk_pm_dev_enable(void); ++ ++/** @brief Disable OS controlled runtime power management ++ */ ++void _mali_osk_pm_dev_disable(void); ++ ++ ++/** @brief Take a reference to the power manager system for the Mali device. ++ * ++ * When function returns successfully, Mali is ON. ++ * ++ * @note Call \a _mali_osk_pm_dev_ref_dec() to release this reference. ++ */ ++_mali_osk_errcode_t _mali_osk_pm_dev_ref_add(void); ++ ++ ++/** @brief Release the reference to the power manger system for the Mali device. ++ * ++ * When reference count reach zero, the cores can be off. ++ * ++ * @note This must be used to release references taken with \a _mali_osk_pm_dev_ref_add(). ++ */ ++void _mali_osk_pm_dev_ref_dec(void); ++ ++ ++/** @brief Take a reference to the power manager system for the Mali device. ++ * ++ * Will leave the cores powered off if they are already powered off. ++ * ++ * @note Call \a _mali_osk_pm_dev_ref_dec() to release this reference. ++ * ++ * @return MALI_TRUE if the Mali GPU is powered on, otherwise MALI_FALSE. ++ */ ++mali_bool _mali_osk_pm_dev_ref_add_no_power_on(void); ++ ++ ++/** @brief Releasing the reference to the power manger system for the Mali device. ++ * ++ * When reference count reach zero, the cores can be off. ++ * ++ * @note This must be used to release references taken with \a _mali_osk_pm_dev_ref_add_no_power_on(). ++ */ ++void _mali_osk_pm_dev_ref_dec_no_power_on(void); ++ ++/** @brief Block untill pending PM operations are done ++ */ ++void _mali_osk_pm_dev_barrier(void); ++ ++/** @} */ /* end group _mali_osk_miscellaneous */ ++ ++/** @} */ /* end group osuapi */ ++ ++/** @} */ /* end group uddapi */ ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++/* Check standard inlines */ ++#ifndef MALI_STATIC_INLINE ++#error MALI_STATIC_INLINE not defined on your OS ++#endif ++ ++#ifndef MALI_NON_STATIC_INLINE ++#error MALI_NON_STATIC_INLINE not defined on your OS ++#endif ++ ++#endif /* __MALI_OSK_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_bitops.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_bitops.h +new file mode 100644 +index 0000000..35f2e67 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_bitops.h +@@ -0,0 +1,162 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_bitops.h ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#ifndef __MALI_OSK_BITOPS_H__ ++#define __MALI_OSK_BITOPS_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++MALI_STATIC_INLINE void _mali_internal_clear_bit( u32 bit, u32 *addr ) ++{ ++ MALI_DEBUG_ASSERT( bit < 32 ); ++ MALI_DEBUG_ASSERT( NULL != addr ); ++ ++ (*addr) &= ~(1 << bit); ++} ++ ++MALI_STATIC_INLINE void _mali_internal_set_bit( u32 bit, u32 *addr ) ++{ ++ MALI_DEBUG_ASSERT( bit < 32 ); ++ MALI_DEBUG_ASSERT( NULL != addr ); ++ ++ (*addr) |= (1 << bit); ++} ++ ++MALI_STATIC_INLINE u32 _mali_internal_test_bit( u32 bit, u32 value ) ++{ ++ MALI_DEBUG_ASSERT( bit < 32 ); ++ return value & (1 << bit); ++} ++ ++MALI_STATIC_INLINE int _mali_internal_find_first_zero_bit( u32 value ) ++{ ++ u32 inverted; ++ u32 negated; ++ u32 isolated; ++ u32 leading_zeros; ++ ++ /* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range 0..31 */ ++ inverted = ~value; /* zzz...z1000...0 */ ++ /* Using count_trailing_zeros on inverted value - ++ * See ARM System Developers Guide for details of count_trailing_zeros */ ++ ++ /* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */ ++ negated = (u32)-inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */ ++ /* negated = xxx...x1000...0 */ ++ ++ isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */ ++ /* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it ++ * Note that the output is zero if value was all 1s */ ++ ++ leading_zeros = _mali_osk_clz( isolated ); ++ ++ return 31 - leading_zeros; ++} ++ ++ ++/** @defgroup _mali_osk_bitops OSK Non-atomic Bit-operations ++ * @{ */ ++ ++/** ++ * These bit-operations do not work atomically, and so locks must be used if ++ * atomicity is required. ++ * ++ * Reference implementations for Little Endian are provided, and so it should ++ * not normally be necessary to re-implement these. Efficient bit-twiddling ++ * techniques are used where possible, implemented in portable C. ++ * ++ * Note that these reference implementations rely on _mali_osk_clz() being ++ * implemented. ++ */ ++ ++/** @brief Clear a bit in a sequence of 32-bit words ++ * @param nr bit number to clear, starting from the (Little-endian) least ++ * significant bit ++ * @param addr starting point for counting. ++ */ ++MALI_STATIC_INLINE void _mali_osk_clear_nonatomic_bit( u32 nr, u32 *addr ) ++{ ++ addr += nr >> 5; /* find the correct word */ ++ nr = nr & ((1 << 5)-1); /* The bit number within the word */ ++ ++ _mali_internal_clear_bit( nr, addr ); ++} ++ ++/** @brief Set a bit in a sequence of 32-bit words ++ * @param nr bit number to set, starting from the (Little-endian) least ++ * significant bit ++ * @param addr starting point for counting. ++ */ ++MALI_STATIC_INLINE void _mali_osk_set_nonatomic_bit( u32 nr, u32 *addr ) ++{ ++ addr += nr >> 5; /* find the correct word */ ++ nr = nr & ((1 << 5)-1); /* The bit number within the word */ ++ ++ _mali_internal_set_bit( nr, addr ); ++} ++ ++/** @brief Test a bit in a sequence of 32-bit words ++ * @param nr bit number to test, starting from the (Little-endian) least ++ * significant bit ++ * @param addr starting point for counting. ++ * @return zero if bit was clear, non-zero if set. Do not rely on the return ++ * value being related to the actual word under test. ++ */ ++MALI_STATIC_INLINE u32 _mali_osk_test_bit( u32 nr, u32 *addr ) ++{ ++ addr += nr >> 5; /* find the correct word */ ++ nr = nr & ((1 << 5)-1); /* The bit number within the word */ ++ ++ return _mali_internal_test_bit( nr, *addr ); ++} ++ ++/* Return maxbit if not found */ ++/** @brief Find the first zero bit in a sequence of 32-bit words ++ * @param addr starting point for search. ++ * @param maxbit the maximum number of bits to search ++ * @return the number of the first zero bit found, or maxbit if none were found ++ * in the specified range. ++ */ ++MALI_STATIC_INLINE u32 _mali_osk_find_first_zero_bit( const u32 *addr, u32 maxbit ) ++{ ++ u32 total; ++ ++ for ( total = 0; total < maxbit; total += 32, ++addr ) { ++ int result; ++ result = _mali_internal_find_first_zero_bit( *addr ); ++ ++ /* non-negative signifies the bit was found */ ++ if ( result >= 0 ) { ++ total += (u32)result; ++ break; ++ } ++ } ++ ++ /* Now check if we reached maxbit or above */ ++ if ( total >= maxbit ) { ++ total = maxbit; ++ } ++ ++ return total; /* either the found bit nr, or maxbit if not found */ ++} ++/** @} */ /* end group _mali_osk_bitops */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_OSK_BITOPS_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_list.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_list.h +new file mode 100644 +index 0000000..65a1d50 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_list.h +@@ -0,0 +1,273 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_list.h ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#ifndef __MALI_OSK_LIST_H__ ++#define __MALI_OSK_LIST_H__ ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++MALI_STATIC_INLINE void __mali_osk_list_add(_mali_osk_list_t *new_entry, _mali_osk_list_t *prev, _mali_osk_list_t *next) ++{ ++ next->prev = new_entry; ++ new_entry->next = next; ++ new_entry->prev = prev; ++ prev->next = new_entry; ++} ++ ++MALI_STATIC_INLINE void __mali_osk_list_del(_mali_osk_list_t *prev, _mali_osk_list_t *next) ++{ ++ next->prev = prev; ++ prev->next = next; ++} ++ ++/** @addtogroup _mali_osk_list OSK Doubly-Linked Circular Lists ++ * @{ */ ++ ++/** Reference implementations of Doubly-linked Circular Lists are provided. ++ * There is often no need to re-implement these. ++ * ++ * @note The implementation may differ subtly from any lists the OS provides. ++ * For this reason, these lists should not be mixed with OS-specific lists ++ * inside the OSK/UKK implementation. */ ++ ++/** @brief Initialize a list to be a head of an empty list ++ * @param exp the list to initialize. */ ++#define _MALI_OSK_INIT_LIST_HEAD(exp) _mali_osk_list_init(exp) ++ ++/** @brief Define a list variable, which is uninitialized. ++ * @param exp the name of the variable that the list will be defined as. */ ++#define _MALI_OSK_LIST_HEAD(exp) _mali_osk_list_t exp ++ ++/** @brief Define a list variable, which is initialized. ++ * @param exp the name of the variable that the list will be defined as. */ ++#define _MALI_OSK_LIST_HEAD_STATIC_INIT(exp) _mali_osk_list_t exp = { &exp, &exp } ++ ++/** @brief Initialize a list element. ++ * ++ * All list elements must be initialized before use. ++ * ++ * Do not use on any list element that is present in a list without using ++ * _mali_osk_list_del first, otherwise this will break the list. ++ * ++ * @param list the list element to initialize ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_init( _mali_osk_list_t *list ) ++{ ++ list->next = list; ++ list->prev = list; ++} ++ ++/** @brief Insert a single list element after an entry in a list ++ * ++ * As an example, if this is inserted to the head of a list, then this becomes ++ * the first element of the list. ++ * ++ * Do not use to move list elements from one list to another, as it will break ++ * the originating list. ++ * ++ * ++ * @param newlist the list element to insert ++ * @param list the list in which to insert. The new element will be the next ++ * entry in this list ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_add( _mali_osk_list_t *new_entry, _mali_osk_list_t *list ) ++{ ++ __mali_osk_list_add(new_entry, list, list->next); ++} ++ ++/** @brief Insert a single list element before an entry in a list ++ * ++ * As an example, if this is inserted to the head of a list, then this becomes ++ * the last element of the list. ++ * ++ * Do not use to move list elements from one list to another, as it will break ++ * the originating list. ++ * ++ * @param newlist the list element to insert ++ * @param list the list in which to insert. The new element will be the previous ++ * entry in this list ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_addtail( _mali_osk_list_t *new_entry, _mali_osk_list_t *list ) ++{ ++ __mali_osk_list_add(new_entry, list->prev, list); ++} ++ ++/** @brief Remove a single element from a list ++ * ++ * The element will no longer be present in the list. The removed list element ++ * will be uninitialized, and so should not be traversed. It must be ++ * initialized before further use. ++ * ++ * @param list the list element to remove. ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_del( _mali_osk_list_t *list ) ++{ ++ __mali_osk_list_del(list->prev, list->next); ++} ++ ++/** @brief Remove a single element from a list, and re-initialize it ++ * ++ * The element will no longer be present in the list. The removed list element ++ * will initialized, and so can be used as normal. ++ * ++ * @param list the list element to remove and initialize. ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_delinit( _mali_osk_list_t *list ) ++{ ++ __mali_osk_list_del(list->prev, list->next); ++ _mali_osk_list_init(list); ++} ++ ++/** @brief Determine whether a list is empty. ++ * ++ * An empty list is one that contains a single element that points to itself. ++ * ++ * @param list the list to check. ++ * @return non-zero if the list is empty, and zero otherwise. ++ */ ++MALI_STATIC_INLINE mali_bool _mali_osk_list_empty( _mali_osk_list_t *list ) ++{ ++ return list->next == list; ++} ++ ++/** @brief Move a list element from one list to another. ++ * ++ * The list element must be initialized. ++ * ++ * As an example, moving a list item to the head of a new list causes this item ++ * to be the first element in the new list. ++ * ++ * @param move the list element to move ++ * @param list the new list into which the element will be inserted, as the next ++ * element in the list. ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_move( _mali_osk_list_t *move_entry, _mali_osk_list_t *list ) ++{ ++ __mali_osk_list_del(move_entry->prev, move_entry->next); ++ _mali_osk_list_add(move_entry, list); ++} ++ ++/** @brief Move an entire list ++ * ++ * The list element must be initialized. ++ * ++ * Allows you to move a list from one list head to another list head ++ * ++ * @param old_list The existing list head ++ * @param new_list The new list head (must be an empty list) ++ */ ++MALI_STATIC_INLINE void _mali_osk_list_move_list( _mali_osk_list_t *old_list, _mali_osk_list_t *new_list ) ++{ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(new_list)); ++ if (!_mali_osk_list_empty(old_list)) { ++ new_list->next = old_list->next; ++ new_list->prev = old_list->prev; ++ new_list->next->prev = new_list; ++ new_list->prev->next = new_list; ++ old_list->next = old_list; ++ old_list->prev = old_list; ++ } ++} ++ ++/** @brief Find the containing structure of a list ++ * ++ * When traversing a list, this is used to recover the containing structure, ++ * given that is contains a _mali_osk_list_t member. ++ * ++ * Each list must be of structures of one type, and must link the same members ++ * together, otherwise it will not be possible to correctly recover the ++ * sturctures that the lists link. ++ * ++ * @note no type or memory checking occurs to ensure that a structure does in ++ * fact exist for the list entry, and that it is being recovered with respect ++ * to the correct list member. ++ * ++ * @param ptr the pointer to the _mali_osk_list_t member in this structure ++ * @param type the type of the structure that contains the member ++ * @param member the member of the structure that ptr points to. ++ * @return a pointer to a \a type object which contains the _mali_osk_list_t ++ * \a member, as pointed to by the _mali_osk_list_t \a *ptr. ++ */ ++#define _MALI_OSK_LIST_ENTRY(ptr, type, member) \ ++ _MALI_OSK_CONTAINER_OF(ptr, type, member) ++ ++/** @brief Enumerate a list safely ++ * ++ * With this macro, lists can be enumerated in a 'safe' manner. That is, ++ * entries can be deleted from the list without causing an error during ++ * enumeration. To achieve this, a 'temporary' pointer is required, which must ++ * be provided to the macro. ++ * ++ * Use it like a 'for()', 'while()' or 'do()' construct, and so it must be ++ * followed by a statement or compound-statement which will be executed for ++ * each list entry. ++ * ++ * Upon loop completion, providing that an early out was not taken in the ++ * loop body, then it is guaranteed that ptr->member == list, even if the loop ++ * body never executed. ++ * ++ * @param ptr a pointer to an object of type 'type', which points to the ++ * structure that contains the currently enumerated list entry. ++ * @param tmp a pointer to an object of type 'type', which must not be used ++ * inside the list-execution statement. ++ * @param list a pointer to a _mali_osk_list_t, from which enumeration will ++ * begin ++ * @param type the type of the structure that contains the _mali_osk_list_t ++ * member that is part of the list to be enumerated. ++ * @param member the _mali_osk_list_t member of the structure that is part of ++ * the list to be enumerated. ++ */ ++#define _MALI_OSK_LIST_FOREACHENTRY(ptr, tmp, list, type, member) \ ++ for (ptr = _MALI_OSK_LIST_ENTRY((list)->next, type, member), \ ++ tmp = _MALI_OSK_LIST_ENTRY(ptr->member.next, type, member); \ ++ &ptr->member != (list); \ ++ ptr = tmp, \ ++ tmp = _MALI_OSK_LIST_ENTRY(tmp->member.next, type, member)) ++ ++/** @brief Enumerate a list in reverse order safely ++ * ++ * This macro is identical to @ref _MALI_OSK_LIST_FOREACHENTRY, except that ++ * entries are enumerated in reverse order. ++ * ++ * @param ptr a pointer to an object of type 'type', which points to the ++ * structure that contains the currently enumerated list entry. ++ * @param tmp a pointer to an object of type 'type', which must not be used ++ * inside the list-execution statement. ++ * @param list a pointer to a _mali_osk_list_t, from which enumeration will ++ * begin ++ * @param type the type of the structure that contains the _mali_osk_list_t ++ * member that is part of the list to be enumerated. ++ * @param member the _mali_osk_list_t member of the structure that is part of ++ * the list to be enumerated. ++ */ ++#define _MALI_OSK_LIST_FOREACHENTRY_REVERSE(ptr, tmp, list, type, member) \ ++ for (ptr = _MALI_OSK_LIST_ENTRY((list)->prev, type, member), \ ++ tmp = _MALI_OSK_LIST_ENTRY(ptr->member.prev, type, member); \ ++ &ptr->member != (list); \ ++ ptr = tmp, \ ++ tmp = _MALI_OSK_LIST_ENTRY(tmp->member.prev, type, member)) ++ ++/** @} */ /* end group _mali_osk_list */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_OSK_LIST_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_mali.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_mali.h +new file mode 100644 +index 0000000..7ed701c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_mali.h +@@ -0,0 +1,118 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_mali.h ++ * Defines the OS abstraction layer which is specific for the Mali kernel device driver (OSK) ++ */ ++ ++#ifndef __MALI_OSK_MALI_H__ ++#define __MALI_OSK_MALI_H__ ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** @addtogroup _mali_osk_miscellaneous ++ * @{ */ ++ ++/** @brief Struct with device specific configuration data ++ */ ++struct _mali_osk_device_data { ++ /* Dedicated GPU memory range (physical). */ ++ u32 dedicated_mem_start; ++ u32 dedicated_mem_size; ++ ++ /* Shared GPU memory */ ++ u32 shared_mem_size; ++ ++ /* Frame buffer memory to be accessible by Mali GPU (physical) */ ++ u32 fb_start; ++ u32 fb_size; ++ ++ /* Max runtime [ms] for jobs */ ++ int max_job_runtime; ++ ++ /* Report GPU utilization in this interval (specified in ms) */ ++ u32 utilization_interval; ++ ++ /* Function that will receive periodic GPU utilization numbers */ ++ void (*utilization_callback)(struct mali_gpu_utilization_data *data); ++ ++ /* ++ * Mali PMU switch delay. ++ * Only needed if the power gates are connected to the PMU in a high fanout ++ * network. This value is the number of Mali clock cycles it takes to ++ * enable the power gates and turn on the power mesh. ++ * This value will have no effect if a daisy chain implementation is used. ++ */ ++ u32 pmu_switch_delay; ++ ++ /* Mali Dynamic power domain configuration in sequence from 0-11 ++ * GP PP0 PP1 PP2 PP3 PP4 PP5 PP6 PP7, L2$0 L2$1 L2$2 ++ */ ++ u16 pmu_domain_config[12]; ++ ++ /* Fuction that platform callback for freq tunning, needed when MALI400_POWER_PERFORMANCE_POLICY enabled */ ++ int (*set_freq_callback)(unsigned int mhz); ++}; ++ ++/** @brief Find Mali GPU HW resource ++ * ++ * @param addr Address of Mali GPU resource to find ++ * @param res Storage for resource information if resource is found. ++ * @return _MALI_OSK_ERR_OK on success, _MALI_OSK_ERR_ITEM_NOT_FOUND if resource is not found ++ */ ++_mali_osk_errcode_t _mali_osk_resource_find(u32 addr, _mali_osk_resource_t *res); ++ ++ ++/** @brief Find Mali GPU HW base address ++ * ++ * @return 0 if resources are found, otherwise the Mali GPU component with lowest address. ++ */ ++u32 _mali_osk_resource_base_address(void); ++ ++/** @brief Retrieve the Mali GPU specific data ++ * ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_device_data_get(struct _mali_osk_device_data *data); ++ ++/** @brief Determines if Mali GPU has been configured with shared interrupts. ++ * ++ * @return MALI_TRUE if shared interrupts, MALI_FALSE if not. ++ */ ++mali_bool _mali_osk_shared_interrupts(void); ++ ++/** @} */ /* end group _mali_osk_miscellaneous */ ++ ++/** @addtogroup _mali_osk_low_level_memory ++ * @{ */ ++ ++/** @brief Copy as much data as possible from src to dest, do not crash if src or dest isn't available. ++ * ++ * @param dest Destination buffer (limited to user space mapped Mali memory) ++ * @param src Source buffer ++ * @param size Number of bytes to copy ++ * @return Number of bytes actually copied ++ */ ++u32 _mali_osk_mem_write_safe(void *dest, const void *src, u32 size); ++ ++/** @} */ /* end group _mali_osk_low_level_memory */ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_OSK_MALI_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_profiling.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_profiling.h +new file mode 100644 +index 0000000..520cd5e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_profiling.h +@@ -0,0 +1,141 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_OSK_PROFILING_H__ ++#define __MALI_OSK_PROFILING_H__ ++ ++#if defined(CONFIG_MALI400_PROFILING) && defined (CONFIG_TRACEPOINTS) ++ ++#include "mali_linux_trace.h" ++#include "mali_profiling_events.h" ++#include "mali_profiling_gator_api.h" ++ ++#define MALI_PROFILING_MAX_BUFFER_ENTRIES 1048576 ++ ++#define MALI_PROFILING_NO_HW_COUNTER = ((u32)-1) ++ ++/** @defgroup _mali_osk_profiling External profiling connectivity ++ * @{ */ ++ ++/** ++ * Initialize the profiling module. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start); ++ ++/* ++ * Terminate the profiling module. ++ */ ++void _mali_osk_profiling_term(void); ++ ++/** ++ * Start recording profiling data ++ * ++ * The specified limit will determine how large the capture buffer is. ++ * MALI_PROFILING_MAX_BUFFER_ENTRIES determines the maximum size allowed by the device driver. ++ * ++ * @param limit The desired maximum number of events to record on input, the actual maximum on output. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit); ++ ++/** ++ * Add an profiling event ++ * ++ * @param event_id The event identificator. ++ * @param data0 First data parameter, depending on event_id specified. ++ * @param data1 Second data parameter, depending on event_id specified. ++ * @param data2 Third data parameter, depending on event_id specified. ++ * @param data3 Fourth data parameter, depending on event_id specified. ++ * @param data4 Fifth data parameter, depending on event_id specified. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++/* Call Linux tracepoint directly */ ++#define _mali_osk_profiling_add_event(event_id, data0, data1, data2, data3, data4) trace_mali_timeline_event((event_id), (data0), (data1), (data2), (data3), (data4)) ++ ++/** ++ * Report a hardware counter event. ++ * ++ * @param counter_id The ID of the counter. ++ * @param value The value of the counter. ++ */ ++ ++/* Call Linux tracepoint directly */ ++#define _mali_osk_profiling_report_hw_counter(counter_id, value) trace_mali_hw_counter(counter_id, value) ++ ++/** ++ * Report SW counters ++ * ++ * @param counters array of counter values ++ */ ++void _mali_osk_profiling_report_sw_counters(u32 *counters); ++ ++/** ++ * Stop recording profiling data ++ * ++ * @param count Returns the number of recorded events. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_profiling_stop(u32 * count); ++ ++/** ++ * Retrieves the number of events that can be retrieved ++ * ++ * @return The number of recorded events that can be retrieved. ++ */ ++u32 _mali_osk_profiling_get_count(void); ++ ++/** ++ * Retrieve an event ++ * ++ * @param index Event index (start with 0 and continue until this function fails to retrieve all events) ++ * @param timestamp The timestamp for the retrieved event will be stored here. ++ * @param event_id The event ID for the retrieved event will be stored here. ++ * @param data The 5 data values for the retrieved event will be stored here. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); ++ ++/** ++ * Clear the recorded buffer. ++ * ++ * This is needed in order to start another recording. ++ * ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t _mali_osk_profiling_clear(void); ++ ++/** ++ * Checks if a recording of profiling data is in progress ++ * ++ * @return MALI_TRUE if recording of profiling data is in progress, MALI_FALSE if not ++ */ ++mali_bool _mali_osk_profiling_is_recording(void); ++ ++/** ++ * Checks if profiling data is available for retrival ++ * ++ * @return MALI_TRUE if profiling data is avaiable, MALI_FALSE if not ++ */ ++mali_bool _mali_osk_profiling_have_recording(void); ++ ++/** @} */ /* end group _mali_osk_profiling */ ++ ++#else /* defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_TRACEPOINTS) */ ++ ++/* Dummy add_event, for when profiling is disabled. */ ++ ++#define _mali_osk_profiling_add_event(event_id, data0, data1, data2, data3, data4) ++ ++#endif /* defined(CONFIG_MALI400_PROFILING) && defined(CONFIG_TRACEPOINTS) */ ++ ++#endif /* __MALI_OSK_PROFILING_H__ */ ++ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_types.h +new file mode 100644 +index 0000000..6d64cd9 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_osk_types.h +@@ -0,0 +1,455 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_types.h ++ * Defines types of the OS abstraction layer for the kernel device driver (OSK) ++ */ ++ ++#ifndef __MALI_OSK_TYPES_H__ ++#define __MALI_OSK_TYPES_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * @addtogroup uddapi Unified Device Driver (UDD) APIs ++ * ++ * @{ ++ */ ++ ++/** ++ * @addtogroup oskapi UDD OS Abstraction for Kernel-side (OSK) APIs ++ * ++ * @{ ++ */ ++ ++/** @defgroup _mali_osk_miscellaneous OSK Miscellaneous functions, constants and types ++ * @{ */ ++ ++/* Define integer types used by OSK. Note: these currently clash with Linux so we only define them if not defined already */ ++#ifndef __KERNEL__ ++typedef unsigned char u8; ++typedef signed char s8; ++typedef unsigned short u16; ++typedef signed short s16; ++typedef unsigned int u32; ++typedef signed int s32; ++typedef unsigned long long u64; ++#define BITS_PER_LONG (sizeof(long)*8) ++#else ++/* Ensure Linux types u32, etc. are defined */ ++#include ++#endif ++ ++/** @brief Mali Boolean type which uses MALI_TRUE and MALI_FALSE ++ */ ++typedef unsigned long mali_bool; ++ ++#ifndef MALI_TRUE ++#define MALI_TRUE ((mali_bool)1) ++#endif ++ ++#ifndef MALI_FALSE ++#define MALI_FALSE ((mali_bool)0) ++#endif ++ ++#define MALI_HW_CORE_NO_COUNTER ((u32)-1) ++ ++/** ++ * @brief OSK Error codes ++ * ++ * Each OS may use its own set of error codes, and may require that the ++ * User/Kernel interface take certain error code. This means that the common ++ * error codes need to be sufficiently rich to pass the correct error code ++ * thorugh from the OSK to U/K layer, across all OSs. ++ * ++ * The result is that some error codes will appear redundant on some OSs. ++ * Under all OSs, the OSK layer must translate native OS error codes to ++ * _mali_osk_errcode_t codes. Similarly, the U/K layer must translate from ++ * _mali_osk_errcode_t codes to native OS error codes. ++ */ ++typedef enum { ++ _MALI_OSK_ERR_OK = 0, /**< Success. */ ++ _MALI_OSK_ERR_FAULT = -1, /**< General non-success */ ++ _MALI_OSK_ERR_INVALID_FUNC = -2, /**< Invalid function requested through User/Kernel interface (e.g. bad IOCTL number) */ ++ _MALI_OSK_ERR_INVALID_ARGS = -3, /**< Invalid arguments passed through User/Kernel interface */ ++ _MALI_OSK_ERR_NOMEM = -4, /**< Insufficient memory */ ++ _MALI_OSK_ERR_TIMEOUT = -5, /**< Timeout occurred */ ++ _MALI_OSK_ERR_RESTARTSYSCALL = -6, /**< Special: On certain OSs, must report when an interruptable mutex is interrupted. Ignore otherwise. */ ++ _MALI_OSK_ERR_ITEM_NOT_FOUND = -7, /**< Table Lookup failed */ ++ _MALI_OSK_ERR_BUSY = -8, /**< Device/operation is busy. Try again later */ ++ _MALI_OSK_ERR_UNSUPPORTED = -9, /**< Optional part of the interface used, and is unsupported */ ++} _mali_osk_errcode_t; ++ ++/** @} */ /* end group _mali_osk_miscellaneous */ ++ ++/** @defgroup _mali_osk_wq OSK work queues ++ * @{ */ ++ ++/** @brief Private type for work objects */ ++typedef struct _mali_osk_wq_work_s _mali_osk_wq_work_t; ++typedef struct _mali_osk_wq_delayed_work_s _mali_osk_wq_delayed_work_t; ++ ++/** @brief Work queue handler function ++ * ++ * This function type is called when the work is scheduled by the work queue, ++ * e.g. as an IRQ bottom-half handler. ++ * ++ * Refer to \ref _mali_osk_wq_schedule_work() for more information on the ++ * work-queue and work handlers. ++ * ++ * @param arg resource-specific data ++ */ ++typedef void (*_mali_osk_wq_work_handler_t)( void * arg ); ++ ++/* @} */ /* end group _mali_osk_wq */ ++ ++/** @defgroup _mali_osk_irq OSK IRQ handling ++ * @{ */ ++ ++/** @brief Private type for IRQ handling objects */ ++typedef struct _mali_osk_irq_t_struct _mali_osk_irq_t; ++ ++/** @brief Optional function to trigger an irq from a resource ++ * ++ * This function is implemented by the common layer to allow probing of a resource's IRQ. ++ * @param arg resource-specific data */ ++typedef void (*_mali_osk_irq_trigger_t)( void * arg ); ++ ++/** @brief Optional function to acknowledge an irq from a resource ++ * ++ * This function is implemented by the common layer to allow probing of a resource's IRQ. ++ * @param arg resource-specific data ++ * @return _MALI_OSK_ERR_OK if the IRQ was successful, or a suitable _mali_osk_errcode_t on failure. */ ++typedef _mali_osk_errcode_t (*_mali_osk_irq_ack_t)( void * arg ); ++ ++/** @brief IRQ 'upper-half' handler callback. ++ * ++ * This function is implemented by the common layer to do the initial handling of a ++ * resource's IRQ. This maps on to the concept of an ISR that does the minimum ++ * work necessary before handing off to an IST. ++ * ++ * The communication of the resource-specific data from the ISR to the IST is ++ * handled by the OSK implementation. ++ * ++ * On most systems, the IRQ upper-half handler executes in IRQ context. ++ * Therefore, the system may have restrictions about what can be done in this ++ * context ++ * ++ * If an IRQ upper-half handler requires more work to be done than can be ++ * acheived in an IRQ context, then it may defer the work with ++ * _mali_osk_wq_schedule_work(). Refer to \ref _mali_osk_wq_create_work() for ++ * more information. ++ * ++ * @param arg resource-specific data ++ * @return _MALI_OSK_ERR_OK if the IRQ was correctly handled, or a suitable ++ * _mali_osk_errcode_t otherwise. ++ */ ++typedef _mali_osk_errcode_t (*_mali_osk_irq_uhandler_t)( void * arg ); ++ ++ ++/** @} */ /* end group _mali_osk_irq */ ++ ++ ++/** @defgroup _mali_osk_atomic OSK Atomic counters ++ * @{ */ ++ ++/** @brief Public type of atomic counters ++ * ++ * This is public for allocation on stack. On systems that support it, this is just a single 32-bit value. ++ * On others, it could be encapsulating an object stored elsewhere. ++ * ++ * Regardless of implementation, the \ref _mali_osk_atomic functions \b must be used ++ * for all accesses to the variable's value, even if atomicity is not required. ++ * Do not access u.val or u.obj directly. ++ */ ++typedef struct { ++ union { ++ u32 val; ++ void *obj; ++ } u; ++} _mali_osk_atomic_t; ++/** @} */ /* end group _mali_osk_atomic */ ++ ++ ++/** @defgroup _mali_osk_lock OSK Mutual Exclusion Locks ++ * @{ */ ++ ++ ++/** @brief OSK Mutual Exclusion Lock ordered list ++ * ++ * This lists the various types of locks in the system and is used to check ++ * that locks are taken in the correct order. ++ * ++ * - Holding more than one lock of the same order at the same time is not ++ * allowed. ++ * - Taking a lock of a lower order than the highest-order lock currently held ++ * is not allowed. ++ * ++ */ ++typedef enum { ++ /* || Locks || */ ++ /* || must be || */ ++ /* _||_ taken in _||_ */ ++ /* \ / this \ / */ ++ /* \/ order! \/ */ ++ ++ _MALI_OSK_LOCK_ORDER_FIRST = 0, ++ ++ _MALI_OSK_LOCK_ORDER_SESSIONS, ++ _MALI_OSK_LOCK_ORDER_MEM_SESSION, ++ _MALI_OSK_LOCK_ORDER_MEM_INFO, ++ _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE, ++ _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP, ++ _MALI_OSK_LOCK_ORDER_GROUP_VIRTUAL, ++ _MALI_OSK_LOCK_ORDER_GROUP, ++ _MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM, ++ _MALI_OSK_LOCK_ORDER_SCHEDULER, ++ _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED, ++ _MALI_OSK_LOCK_ORDER_PM_CORE_STATE, ++ _MALI_OSK_LOCK_ORDER_L2_COMMAND, ++ _MALI_OSK_LOCK_ORDER_DMA_COMMAND, ++ _MALI_OSK_LOCK_ORDER_PROFILING, ++ _MALI_OSK_LOCK_ORDER_L2_COUNTER, ++ _MALI_OSK_LOCK_ORDER_UTILIZATION, ++ _MALI_OSK_LOCK_ORDER_PM_EXECUTE, ++ _MALI_OSK_LOCK_ORDER_SESSION_PENDING_JOBS, ++ _MALI_OSK_LOCK_ORDER_PM_DOMAIN, ++ _MALI_OSK_LOCK_ORDER_PMU, ++ ++ _MALI_OSK_LOCK_ORDER_LAST, ++} _mali_osk_lock_order_t; ++ ++ ++/** @brief OSK Mutual Exclusion Lock flags type ++ * ++ * - Any lock can use the order parameter. ++ */ ++typedef enum { ++ _MALI_OSK_LOCKFLAG_UNORDERED = 0x1, /**< Indicate that the order of this lock should not be checked */ ++ _MALI_OSK_LOCKFLAG_ORDERED = 0x2, ++ /** @enum _mali_osk_lock_flags_t ++ * ++ * Flags from 0x10000--0x80000000 are RESERVED for User-mode */ ++ ++} _mali_osk_lock_flags_t; ++ ++/** @brief Mutual Exclusion Lock Mode Optimization hint ++ * ++ * The lock mode is used to implement the read/write locking of locks when we call ++ * functions _mali_osk_mutex_rw_init/wait/signal/term/. In this case, the RO mode can ++ * be used to allow multiple concurrent readers, but no writers. The RW mode is used for ++ * writers, and so will wait for all readers to release the lock (if any present). ++ * Further readers and writers will wait until the writer releases the lock. ++ * ++ * The mode is purely an optimization hint: for example, it is permissible for ++ * all locks to behave in RW mode, regardless of that supplied. ++ * ++ * It is an error to attempt to use locks in anything other that RW mode when ++ * call functions _mali_osk_mutex_rw_wait/signal(). ++ * ++ */ ++typedef enum { ++ _MALI_OSK_LOCKMODE_UNDEF = -1, /**< Undefined lock mode. For internal use only */ ++ _MALI_OSK_LOCKMODE_RW = 0x0, /**< Read-write mode, default. All readers and writers are mutually-exclusive */ ++ _MALI_OSK_LOCKMODE_RO, /**< Read-only mode, to support multiple concurrent readers, but mutual exclusion in the presence of writers. */ ++ /** @enum _mali_osk_lock_mode_t ++ * ++ * Lock modes 0x40--0x7F are RESERVED for User-mode */ ++} _mali_osk_lock_mode_t; ++ ++/** @brief Private types for Mutual Exclusion lock objects */ ++typedef struct _mali_osk_lock_debug_s _mali_osk_lock_debug_t; ++typedef struct _mali_osk_spinlock_s _mali_osk_spinlock_t; ++typedef struct _mali_osk_spinlock_irq_s _mali_osk_spinlock_irq_t; ++typedef struct _mali_osk_mutex_s _mali_osk_mutex_t; ++typedef struct _mali_osk_mutex_rw_s _mali_osk_mutex_rw_t; ++ ++/** @} */ /* end group _mali_osk_lock */ ++ ++/** @defgroup _mali_osk_low_level_memory OSK Low-level Memory Operations ++ * @{ */ ++ ++/** ++ * @brief Private data type for use in IO accesses to/from devices. ++ * ++ * This represents some range that is accessible from the device. Examples ++ * include: ++ * - Device Registers, which could be readable and/or writeable. ++ * - Memory that the device has access to, for storing configuration structures. ++ * ++ * Access to this range must be made through the _mali_osk_mem_ioread32() and ++ * _mali_osk_mem_iowrite32() functions. ++ */ ++typedef struct _mali_io_address * mali_io_address; ++ ++/** @defgroup _MALI_OSK_CPU_PAGE CPU Physical page size macros. ++ * ++ * The order of the page size is supplied for ++ * ease of use by algorithms that might require it, since it is easier to know ++ * it ahead of time rather than calculating it. ++ * ++ * The Mali Page Mask macro masks off the lower bits of a physical address to ++ * give the start address of the page for that physical address. ++ * ++ * @note The Mali device driver code is designed for systems with 4KB page size. ++ * Changing these macros will not make the entire Mali device driver work with ++ * page sizes other than 4KB. ++ * ++ * @note The CPU Physical Page Size has been assumed to be the same as the Mali ++ * Physical Page Size. ++ * ++ * @{ ++ */ ++ ++/** CPU Page Order, as log to base 2 of the Page size. @see _MALI_OSK_CPU_PAGE_SIZE */ ++#define _MALI_OSK_CPU_PAGE_ORDER ((u32)12) ++/** CPU Page Size, in bytes. */ ++#define _MALI_OSK_CPU_PAGE_SIZE (((u32)1) << (_MALI_OSK_CPU_PAGE_ORDER)) ++/** CPU Page Mask, which masks off the offset within a page */ ++#define _MALI_OSK_CPU_PAGE_MASK (~((((u32)1) << (_MALI_OSK_CPU_PAGE_ORDER)) - ((u32)1))) ++/** @} */ /* end of group _MALI_OSK_CPU_PAGE */ ++ ++/** @defgroup _MALI_OSK_MALI_PAGE Mali Physical Page size macros ++ * ++ * Mali Physical page size macros. The order of the page size is supplied for ++ * ease of use by algorithms that might require it, since it is easier to know ++ * it ahead of time rather than calculating it. ++ * ++ * The Mali Page Mask macro masks off the lower bits of a physical address to ++ * give the start address of the page for that physical address. ++ * ++ * @note The Mali device driver code is designed for systems with 4KB page size. ++ * Changing these macros will not make the entire Mali device driver work with ++ * page sizes other than 4KB. ++ * ++ * @note The Mali Physical Page Size has been assumed to be the same as the CPU ++ * Physical Page Size. ++ * ++ * @{ ++ */ ++ ++/** Mali Page Order, as log to base 2 of the Page size. @see _MALI_OSK_MALI_PAGE_SIZE */ ++#define _MALI_OSK_MALI_PAGE_ORDER ((u32)12) ++/** Mali Page Size, in bytes. */ ++#define _MALI_OSK_MALI_PAGE_SIZE (((u32)1) << (_MALI_OSK_MALI_PAGE_ORDER)) ++/** Mali Page Mask, which masks off the offset within a page */ ++#define _MALI_OSK_MALI_PAGE_MASK (~((((u32)1) << (_MALI_OSK_MALI_PAGE_ORDER)) - ((u32)1))) ++/** @} */ /* end of group _MALI_OSK_MALI_PAGE*/ ++ ++/** @brief flags for mapping a user-accessible memory range ++ * ++ * Where a function with prefix '_mali_osk_mem_mapregion' accepts flags as one ++ * of the function parameters, it will use one of these. These allow per-page ++ * control over mappings. Compare with the mali_memory_allocation_flag type, ++ * which acts over an entire range ++ * ++ * These may be OR'd together with bitwise OR (|), but must be cast back into ++ * the type after OR'ing. ++ */ ++typedef enum { ++ _MALI_OSK_MEM_MAPREGION_FLAG_OS_ALLOCATED_PHYSADDR = 0x1, /**< Physical address is OS Allocated */ ++} _mali_osk_mem_mapregion_flags_t; ++/** @} */ /* end group _mali_osk_low_level_memory */ ++ ++/** @defgroup _mali_osk_notification OSK Notification Queues ++ * @{ */ ++ ++/** @brief Private type for notification queue objects */ ++typedef struct _mali_osk_notification_queue_t_struct _mali_osk_notification_queue_t; ++ ++/** @brief Public notification data object type */ ++typedef struct _mali_osk_notification_t_struct { ++ u32 notification_type; /**< The notification type */ ++ u32 result_buffer_size; /**< Size of the result buffer to copy to user space */ ++ void * result_buffer; /**< Buffer containing any type specific data */ ++} _mali_osk_notification_t; ++ ++/** @} */ /* end group _mali_osk_notification */ ++ ++ ++/** @defgroup _mali_osk_timer OSK Timer Callbacks ++ * @{ */ ++ ++/** @brief Function to call when a timer expires ++ * ++ * When a timer expires, this function is called. Note that on many systems, ++ * a timer callback will be executed in IRQ context. Therefore, restrictions ++ * may apply on what can be done inside the timer callback. ++ * ++ * If a timer requires more work to be done than can be acheived in an IRQ ++ * context, then it may defer the work with a work-queue. For example, it may ++ * use \ref _mali_osk_wq_schedule_work() to make use of a bottom-half handler ++ * to carry out the remaining work. ++ * ++ * Stopping the timer with \ref _mali_osk_timer_del() blocks on compeletion of ++ * the callback. Therefore, the callback may not obtain any mutexes also held ++ * by any callers of _mali_osk_timer_del(). Otherwise, a deadlock may occur. ++ * ++ * @param arg Function-specific data */ ++typedef void (*_mali_osk_timer_callback_t)(void * arg); ++ ++/** @brief Private type for Timer Callback Objects */ ++typedef struct _mali_osk_timer_t_struct _mali_osk_timer_t; ++/** @} */ /* end group _mali_osk_timer */ ++ ++ ++/** @addtogroup _mali_osk_list OSK Doubly-Linked Circular Lists ++ * @{ */ ++ ++/** @brief Public List objects. ++ * ++ * To use, add a _mali_osk_list_t member to the structure that may become part ++ * of a list. When traversing the _mali_osk_list_t objects, use the ++ * _MALI_OSK_CONTAINER_OF() macro to recover the structure from its ++ *_mali_osk_list_t member ++ * ++ * Each structure may have multiple _mali_osk_list_t members, so that the ++ * structure is part of multiple lists. When traversing lists, ensure that the ++ * correct _mali_osk_list_t member is used, because type-checking will be ++ * lost by the compiler. ++ */ ++typedef struct _mali_osk_list_s { ++ struct _mali_osk_list_s *next; ++ struct _mali_osk_list_s *prev; ++} _mali_osk_list_t; ++/** @} */ /* end group _mali_osk_list */ ++ ++/** @addtogroup _mali_osk_miscellaneous ++ * @{ */ ++ ++/** @brief resource description struct ++ * ++ * Platform independent representation of a Mali HW resource ++ */ ++typedef struct _mali_osk_resource { ++ const char * description; /**< short description of the resource */ ++ u32 base; /**< Physical base address of the resource, as seen by Mali resources. */ ++ u32 irq; /**< IRQ number delivered to the CPU, or -1 to tell the driver to probe for it (if possible) */ ++} _mali_osk_resource_t; ++/** @} */ /* end group _mali_osk_miscellaneous */ ++ ++/** @defgroup _mali_osk_wait_queue OSK Wait Queue functionality ++ * @{ */ ++/** @brief Private type for wait queue objects */ ++typedef struct _mali_osk_wait_queue_t_struct _mali_osk_wait_queue_t; ++/** @} */ /* end group _mali_osk_wait_queue */ ++ ++/** @} */ /* end group osuapi */ ++ ++/** @} */ /* end group uddapi */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_OSK_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.c +new file mode 100644 +index 0000000..7ec2b09 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.c +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_pm.h" ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_gp_scheduler.h" ++#include "mali_pp_scheduler.h" ++#include "mali_scheduler.h" ++#include "mali_kernel_utilization.h" ++#include "mali_group.h" ++#include "mali_pm_domain.h" ++#include "mali_pmu.h" ++ ++static mali_bool mali_power_on = MALI_FALSE; ++ ++_mali_osk_errcode_t mali_pm_initialize(void) ++{ ++ _mali_osk_pm_dev_enable(); ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_pm_terminate(void) ++{ ++ mali_pm_domain_terminate(); ++ _mali_osk_pm_dev_disable(); ++} ++ ++/* Reset GPU after power up */ ++static void mali_pm_reset_gpu(void) ++{ ++ /* Reset all L2 caches */ ++ mali_l2_cache_reset_all(); ++ ++ /* Reset all groups */ ++ mali_scheduler_reset_all_groups(); ++} ++ ++void mali_pm_os_suspend(void) ++{ ++ MALI_DEBUG_PRINT(3, ("Mali PM: OS suspend\n")); ++ mali_gp_scheduler_suspend(); ++ mali_pp_scheduler_suspend(); ++ mali_utilization_suspend(); ++ mali_group_power_off(MALI_TRUE); ++ mali_power_on = MALI_FALSE; ++} ++ ++void mali_pm_os_resume(void) ++{ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ mali_bool do_reset = MALI_FALSE; ++ ++ MALI_DEBUG_PRINT(3, ("Mali PM: OS resume\n")); ++ ++ if (MALI_TRUE != mali_power_on) { ++ do_reset = MALI_TRUE; ++ } ++ ++ if (NULL != pmu) { ++ mali_pmu_reset(pmu); ++ } ++ ++ mali_power_on = MALI_TRUE; ++ _mali_osk_write_mem_barrier(); ++ ++ if (do_reset) { ++ mali_pm_reset_gpu(); ++ mali_group_power_on(); ++ } ++ ++ mali_gp_scheduler_resume(); ++ mali_pp_scheduler_resume(); ++} ++ ++void mali_pm_runtime_suspend(void) ++{ ++ MALI_DEBUG_PRINT(3, ("Mali PM: Runtime suspend\n")); ++ mali_group_power_off(MALI_TRUE); ++ mali_power_on = MALI_FALSE; ++} ++ ++void mali_pm_runtime_resume(void) ++{ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ mali_bool do_reset = MALI_FALSE; ++ ++ MALI_DEBUG_PRINT(3, ("Mali PM: Runtime resume\n")); ++ ++ if (MALI_TRUE != mali_power_on) { ++ do_reset = MALI_TRUE; ++ } ++ ++ if (NULL != pmu) { ++ mali_pmu_reset(pmu); ++ } ++ ++ mali_power_on = MALI_TRUE; ++ _mali_osk_write_mem_barrier(); ++ ++ if (do_reset) { ++ mali_pm_reset_gpu(); ++ mali_group_power_on(); ++ } ++} ++ ++void mali_pm_set_power_is_on(void) ++{ ++ mali_power_on = MALI_TRUE; ++} ++ ++mali_bool mali_pm_is_power_on(void) ++{ ++ return mali_power_on; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.h +new file mode 100644 +index 0000000..1c72aaf +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PM_H__ ++#define __MALI_PM_H__ ++ ++#include "mali_osk.h" ++ ++_mali_osk_errcode_t mali_pm_initialize(void); ++void mali_pm_terminate(void); ++ ++/* Callback functions registered for the runtime PMM system */ ++void mali_pm_os_suspend(void); ++void mali_pm_os_resume(void); ++void mali_pm_runtime_suspend(void); ++void mali_pm_runtime_resume(void); ++ ++void mali_pm_set_power_is_on(void); ++mali_bool mali_pm_is_power_on(void); ++ ++#endif /* __MALI_PM_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.c +new file mode 100644 +index 0000000..0e3f198 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.c +@@ -0,0 +1,241 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_pm_domain.h" ++#include "mali_pmu.h" ++#include "mali_group.h" ++ ++static struct mali_pm_domain *mali_pm_domains[MALI_MAX_NUMBER_OF_DOMAINS] = { NULL, }; ++ ++static void mali_pm_domain_lock(struct mali_pm_domain *domain) ++{ ++ _mali_osk_spinlock_irq_lock(domain->lock); ++} ++ ++static void mali_pm_domain_unlock(struct mali_pm_domain *domain) ++{ ++ _mali_osk_spinlock_irq_unlock(domain->lock); ++} ++ ++MALI_STATIC_INLINE void mali_pm_domain_state_set(struct mali_pm_domain *domain, mali_pm_domain_state state) ++{ ++ domain->state = state; ++} ++ ++struct mali_pm_domain *mali_pm_domain_create(u32 pmu_mask) ++{ ++ struct mali_pm_domain* domain = NULL; ++ u32 domain_id = 0; ++ ++ domain = mali_pm_domain_get_from_mask(pmu_mask); ++ if (NULL != domain) return domain; ++ ++ MALI_DEBUG_PRINT(2, ("Mali PM domain: Creating Mali PM domain (mask=0x%08X)\n", pmu_mask)); ++ ++ domain = (struct mali_pm_domain *)_mali_osk_malloc(sizeof(struct mali_pm_domain)); ++ if (NULL != domain) { ++ domain->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_PM_DOMAIN); ++ if (NULL == domain->lock) { ++ _mali_osk_free(domain); ++ return NULL; ++ } ++ ++ domain->state = MALI_PM_DOMAIN_ON; ++ domain->pmu_mask = pmu_mask; ++ domain->use_count = 0; ++ domain->group_list = NULL; ++ domain->group_count = 0; ++ domain->l2 = NULL; ++ ++ domain_id = _mali_osk_fls(pmu_mask) - 1; ++ /* Verify the domain_id */ ++ MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > domain_id); ++ /* Verify that pmu_mask only one bit is set */ ++ MALI_DEBUG_ASSERT((1 << domain_id) == pmu_mask); ++ mali_pm_domains[domain_id] = domain; ++ ++ return domain; ++ } else { ++ MALI_DEBUG_PRINT_ERROR(("Unable to create PM domain\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_pm_domain_delete(struct mali_pm_domain *domain) ++{ ++ if (NULL == domain) { ++ return; ++ } ++ _mali_osk_spinlock_irq_term(domain->lock); ++ ++ _mali_osk_free(domain); ++} ++ ++void mali_pm_domain_terminate(void) ++{ ++ int i; ++ ++ /* Delete all domains */ ++ for (i = 0; i < MALI_MAX_NUMBER_OF_DOMAINS; i++) { ++ mali_pm_domain_delete(mali_pm_domains[i]); ++ } ++} ++ ++void mali_pm_domain_add_group(u32 mask, struct mali_group *group) ++{ ++ struct mali_pm_domain *domain = mali_pm_domain_get_from_mask(mask); ++ struct mali_group *next; ++ ++ if (NULL == domain) return; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ ++domain->group_count; ++ next = domain->group_list; ++ ++ domain->group_list = group; ++ ++ group->pm_domain_list = next; ++ ++ mali_group_set_pm_domain(group, domain); ++ ++ /* Get pm domain ref after mali_group_set_pm_domain */ ++ mali_group_get_pm_domain_ref(group); ++} ++ ++void mali_pm_domain_add_l2(u32 mask, struct mali_l2_cache_core *l2) ++{ ++ struct mali_pm_domain *domain = mali_pm_domain_get_from_mask(mask); ++ ++ if (NULL == domain) return; ++ ++ MALI_DEBUG_ASSERT(NULL == domain->l2); ++ MALI_DEBUG_ASSERT(NULL != l2); ++ ++ domain->l2 = l2; ++ ++ mali_l2_cache_set_pm_domain(l2, domain); ++} ++ ++struct mali_pm_domain *mali_pm_domain_get_from_mask(u32 mask) ++{ ++ u32 id = 0; ++ ++ if (0 == mask) return NULL; ++ ++ id = _mali_osk_fls(mask)-1; ++ ++ MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > id); ++ /* Verify that pmu_mask only one bit is set */ ++ MALI_DEBUG_ASSERT((1 << id) == mask); ++ ++ return mali_pm_domains[id]; ++} ++ ++struct mali_pm_domain *mali_pm_domain_get_from_index(u32 id) ++{ ++ MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > id); ++ ++ return mali_pm_domains[id]; ++} ++ ++void mali_pm_domain_ref_get(struct mali_pm_domain *domain) ++{ ++ if (NULL == domain) return; ++ ++ mali_pm_domain_lock(domain); ++ ++domain->use_count; ++ ++ if (MALI_PM_DOMAIN_ON != domain->state) { ++ /* Power on */ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ ++ MALI_DEBUG_PRINT(3, ("PM Domain: Powering on 0x%08x\n", domain->pmu_mask)); ++ ++ if (NULL != pmu) { ++ _mali_osk_errcode_t err; ++ ++ err = mali_pmu_power_up(pmu, domain->pmu_mask); ++ ++ if (_MALI_OSK_ERR_OK != err && _MALI_OSK_ERR_BUSY != err) { ++ MALI_PRINT_ERROR(("PM Domain: Failed to power up PM domain 0x%08x\n", ++ domain->pmu_mask)); ++ } ++ } ++ mali_pm_domain_state_set(domain, MALI_PM_DOMAIN_ON); ++ } else { ++ MALI_DEBUG_ASSERT(MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(domain)); ++ } ++ ++ mali_pm_domain_unlock(domain); ++} ++ ++void mali_pm_domain_ref_put(struct mali_pm_domain *domain) ++{ ++ if (NULL == domain) return; ++ ++ mali_pm_domain_lock(domain); ++ --domain->use_count; ++ ++ if (0 == domain->use_count && MALI_PM_DOMAIN_OFF != domain->state) { ++ /* Power off */ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ ++ MALI_DEBUG_PRINT(3, ("PM Domain: Powering off 0x%08x\n", domain->pmu_mask)); ++ ++ mali_pm_domain_state_set(domain, MALI_PM_DOMAIN_OFF); ++ ++ if (NULL != pmu) { ++ _mali_osk_errcode_t err; ++ ++ err = mali_pmu_power_down(pmu, domain->pmu_mask); ++ ++ if (_MALI_OSK_ERR_OK != err && _MALI_OSK_ERR_BUSY != err) { ++ MALI_PRINT_ERROR(("PM Domain: Failed to power down PM domain 0x%08x\n", ++ domain->pmu_mask)); ++ } ++ } ++ } ++ mali_pm_domain_unlock(domain); ++} ++ ++mali_bool mali_pm_domain_lock_state(struct mali_pm_domain *domain) ++{ ++ mali_bool is_powered = MALI_TRUE; ++ ++ /* Take a reference without powering on */ ++ if (NULL != domain) { ++ mali_pm_domain_lock(domain); ++ ++domain->use_count; ++ ++ if (MALI_PM_DOMAIN_ON != domain->state) { ++ is_powered = MALI_FALSE; ++ } ++ mali_pm_domain_unlock(domain); ++ } ++ ++ if(!_mali_osk_pm_dev_ref_add_no_power_on()) { ++ is_powered = MALI_FALSE; ++ } ++ ++ return is_powered; ++} ++ ++void mali_pm_domain_unlock_state(struct mali_pm_domain *domain) ++{ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ ++ if (NULL != domain) { ++ mali_pm_domain_ref_put(domain); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.h +new file mode 100644 +index 0000000..742f96e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pm_domain.h +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PM_DOMAIN_H__ ++#define __MALI_PM_DOMAIN_H__ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++ ++#include "mali_l2_cache.h" ++#include "mali_group.h" ++#include "mali_pmu.h" ++ ++typedef enum { ++ MALI_PM_DOMAIN_ON, ++ MALI_PM_DOMAIN_OFF, ++} mali_pm_domain_state; ++ ++struct mali_pm_domain { ++ mali_pm_domain_state state; ++ _mali_osk_spinlock_irq_t *lock; ++ ++ s32 use_count; ++ ++ u32 pmu_mask; ++ ++ int group_count; ++ struct mali_group *group_list; ++ ++ struct mali_l2_cache_core *l2; ++}; ++ ++struct mali_pm_domain *mali_pm_domain_create(u32 pmu_mask); ++ ++void mali_pm_domain_add_group(u32 mask, struct mali_group *group); ++ ++void mali_pm_domain_add_l2(u32 mask, struct mali_l2_cache_core *l2); ++void mali_pm_domain_delete(struct mali_pm_domain *domain); ++ ++void mali_pm_domain_terminate(void); ++ ++/** Get PM domain from domain ID ++ */ ++struct mali_pm_domain *mali_pm_domain_get_from_mask(u32 mask); ++struct mali_pm_domain *mali_pm_domain_get_from_index(u32 id); ++ ++/* Ref counting */ ++void mali_pm_domain_ref_get(struct mali_pm_domain *domain); ++void mali_pm_domain_ref_put(struct mali_pm_domain *domain); ++ ++MALI_STATIC_INLINE struct mali_l2_cache_core *mali_pm_domain_l2_get(struct mali_pm_domain *domain) ++{ ++ return domain->l2; ++} ++ ++MALI_STATIC_INLINE mali_pm_domain_state mali_pm_domain_state_get(struct mali_pm_domain *domain) ++{ ++ return domain->state; ++} ++ ++mali_bool mali_pm_domain_lock_state(struct mali_pm_domain *domain); ++void mali_pm_domain_unlock_state(struct mali_pm_domain *domain); ++ ++#define MALI_PM_DOMAIN_FOR_EACH_GROUP(group, domain) for ((group) = (domain)->group_list;\ ++ NULL != (group); (group) = (group)->pm_domain_list) ++ ++#endif /* __MALI_PM_DOMAIN_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.c +new file mode 100644 +index 0000000..3c27fc7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.c +@@ -0,0 +1,406 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_pmu.c ++ * Mali driver functions for Mali 400 PMU hardware ++ */ ++#include "mali_hw_core.h" ++#include "mali_pmu.h" ++#include "mali_pp.h" ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_pm.h" ++#include "mali_osk_mali.h" ++ ++u16 mali_pmu_global_domain_config[MALI_MAX_NUMBER_OF_DOMAINS]= {0}; ++ ++static u32 mali_pmu_detect_mask(void); ++ ++/** @brief MALI inbuilt PMU hardware info and PMU hardware has knowledge of cores power mask ++ */ ++struct mali_pmu_core { ++ struct mali_hw_core hw_core; ++ _mali_osk_spinlock_t *lock; ++ u32 registered_cores_mask; ++ u32 active_cores_mask; ++ u32 switch_delay; ++}; ++ ++static struct mali_pmu_core *mali_global_pmu_core = NULL; ++ ++/** @brief Register layout for hardware PMU ++ */ ++typedef enum { ++ PMU_REG_ADDR_MGMT_POWER_UP = 0x00, /*< Power up register */ ++ PMU_REG_ADDR_MGMT_POWER_DOWN = 0x04, /*< Power down register */ ++ PMU_REG_ADDR_MGMT_STATUS = 0x08, /*< Core sleep status register */ ++ PMU_REG_ADDR_MGMT_INT_MASK = 0x0C, /*< Interrupt mask register */ ++ PMU_REG_ADDR_MGMT_INT_RAWSTAT = 0x10, /*< Interrupt raw status register */ ++ PMU_REG_ADDR_MGMT_INT_CLEAR = 0x18, /*< Interrupt clear register */ ++ PMU_REG_ADDR_MGMT_SW_DELAY = 0x1C, /*< Switch delay register */ ++ PMU_REGISTER_ADDRESS_SPACE_SIZE = 0x28, /*< Size of register space */ ++} pmu_reg_addr_mgmt_addr; ++ ++#define PMU_REG_VAL_IRQ 1 ++ ++struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource) ++{ ++ struct mali_pmu_core* pmu; ++ ++ MALI_DEBUG_ASSERT(NULL == mali_global_pmu_core); ++ MALI_DEBUG_PRINT(2, ("Mali PMU: Creating Mali PMU core\n")); ++ ++ pmu = (struct mali_pmu_core *)_mali_osk_malloc(sizeof(struct mali_pmu_core)); ++ if (NULL != pmu) { ++ pmu->lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_PMU); ++ if (NULL != pmu->lock) { ++ pmu->registered_cores_mask = mali_pmu_detect_mask(); ++ pmu->active_cores_mask = pmu->registered_cores_mask; ++ ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&pmu->hw_core, resource, PMU_REGISTER_ADDRESS_SPACE_SIZE)) { ++ _mali_osk_errcode_t err; ++ struct _mali_osk_device_data data = { 0, }; ++ ++ err = _mali_osk_device_data_get(&data); ++ if (_MALI_OSK_ERR_OK == err) { ++ pmu->switch_delay = data.pmu_switch_delay; ++ mali_global_pmu_core = pmu; ++ return pmu; ++ } ++ mali_hw_core_delete(&pmu->hw_core); ++ } ++ _mali_osk_spinlock_term(pmu->lock); ++ } ++ _mali_osk_free(pmu); ++ } ++ ++ return NULL; ++} ++ ++void mali_pmu_delete(struct mali_pmu_core *pmu) ++{ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(pmu == mali_global_pmu_core); ++ MALI_DEBUG_PRINT(2, ("Mali PMU: Deleting Mali PMU core\n")); ++ ++ _mali_osk_spinlock_term(pmu->lock); ++ mali_hw_core_delete(&pmu->hw_core); ++ _mali_osk_free(pmu); ++ mali_global_pmu_core = NULL; ++} ++ ++static void mali_pmu_lock(struct mali_pmu_core *pmu) ++{ ++ _mali_osk_spinlock_lock(pmu->lock); ++} ++static void mali_pmu_unlock(struct mali_pmu_core *pmu) ++{ ++ _mali_osk_spinlock_unlock(pmu->lock); ++} ++ ++static _mali_osk_errcode_t mali_pmu_wait_for_command_finish(struct mali_pmu_core *pmu) ++{ ++ u32 rawstat; ++ u32 timeout = MALI_REG_POLL_COUNT_SLOW; ++ ++ MALI_DEBUG_ASSERT(pmu); ++ ++ /* Wait for the command to complete */ ++ do { ++ rawstat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_RAWSTAT); ++ --timeout; ++ } while (0 == (rawstat & PMU_REG_VAL_IRQ) && 0 < timeout); ++ ++ MALI_DEBUG_ASSERT(0 < timeout); ++ if (0 == timeout) { ++ return _MALI_OSK_ERR_TIMEOUT; ++ } ++ ++ mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_CLEAR, PMU_REG_VAL_IRQ); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_pmu_power_up_internal(struct mali_pmu_core *pmu, const u32 mask) ++{ ++ u32 stat; ++ _mali_osk_errcode_t err; ++#if !defined(CONFIG_MALI_PMU_PARALLEL_POWER_UP) ++ u32 current_domain; ++#endif ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(0 == (mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_RAWSTAT) ++ & PMU_REG_VAL_IRQ)); ++ ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ stat &= pmu->registered_cores_mask; ++ if (0 == mask || 0 == (stat & mask)) return _MALI_OSK_ERR_OK; ++ ++#if defined(CONFIG_MALI_PMU_PARALLEL_POWER_UP) ++ mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_UP, mask); ++ ++ err = mali_pmu_wait_for_command_finish(pmu); ++ if (_MALI_OSK_ERR_OK != err) { ++ return err; ++ } ++#else ++ for (current_domain = 1; current_domain <= pmu->registered_cores_mask; current_domain <<= 1) { ++ if (current_domain & mask & stat) { ++ mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_UP, current_domain); ++ ++ err = mali_pmu_wait_for_command_finish(pmu); ++ if (_MALI_OSK_ERR_OK != err) { ++ return err; ++ } ++ } ++ } ++#endif ++ ++#if defined(DEBUG) ++ /* Get power status of cores */ ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ stat &= pmu->registered_cores_mask; ++ ++ MALI_DEBUG_ASSERT(0 == (stat & mask)); ++ MALI_DEBUG_ASSERT(0 == (stat & pmu->active_cores_mask)); ++#endif /* defined(DEBUG) */ ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static _mali_osk_errcode_t mali_pmu_power_down_internal(struct mali_pmu_core *pmu, const u32 mask) ++{ ++ u32 stat; ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(0 == (mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_RAWSTAT) ++ & PMU_REG_VAL_IRQ)); ++ ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ stat &= pmu->registered_cores_mask; ++ ++ if (0 == mask || 0 == ((~stat) & mask)) return _MALI_OSK_ERR_OK; ++ ++ mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_POWER_DOWN, mask); ++ ++ /* Do not wait for interrupt on Mali-300/400 if all domains are powered off ++ * by our power down command, because the HW will simply not generate an ++ * interrupt in this case.*/ ++ if (mali_is_mali450() || pmu->registered_cores_mask != (mask | stat)) { ++ err = mali_pmu_wait_for_command_finish(pmu); ++ if (_MALI_OSK_ERR_OK != err) { ++ return err; ++ } ++ } else { ++ mali_hw_core_register_write(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_CLEAR, PMU_REG_VAL_IRQ); ++ } ++#if defined(DEBUG) ++ /* Get power status of cores */ ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ stat &= pmu->registered_cores_mask; ++ ++ MALI_DEBUG_ASSERT(mask == (stat & mask)); ++#endif ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu) ++{ ++ _mali_osk_errcode_t err; ++ u32 cores_off_mask, cores_on_mask, stat; ++ ++ mali_pmu_lock(pmu); ++ ++ /* Setup the desired defaults */ ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0); ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_SW_DELAY, pmu->switch_delay); ++ ++ /* Get power status of cores */ ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ ++ cores_off_mask = pmu->registered_cores_mask & ~(stat | pmu->active_cores_mask); ++ cores_on_mask = pmu->registered_cores_mask & (stat & pmu->active_cores_mask); ++ ++ if (0 != cores_off_mask) { ++ err = mali_pmu_power_down_internal(pmu, cores_off_mask); ++ if (_MALI_OSK_ERR_OK != err) return err; ++ } ++ ++ if (0 != cores_on_mask) { ++ err = mali_pmu_power_up_internal(pmu, cores_on_mask); ++ if (_MALI_OSK_ERR_OK != err) return err; ++ } ++ ++#if defined(DEBUG) ++ { ++ stat = mali_hw_core_register_read(&pmu->hw_core, PMU_REG_ADDR_MGMT_STATUS); ++ stat &= pmu->registered_cores_mask; ++ ++ MALI_DEBUG_ASSERT(stat == (pmu->registered_cores_mask & ~pmu->active_cores_mask)); ++ } ++#endif /* defined(DEBUG) */ ++ ++ mali_pmu_unlock(pmu); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_pmu_power_down(struct mali_pmu_core *pmu, u32 mask) ++{ ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0 ); ++ ++ /* Make sure we have a valid power domain mask */ ++ if (mask > pmu->registered_cores_mask) { ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ mali_pmu_lock(pmu); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PMU: Power down (0x%08X)\n", mask)); ++ ++ pmu->active_cores_mask &= ~mask; ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ if (!mali_pm_is_power_on()) { ++ /* Don't touch hardware if all of Mali is powered off. */ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ mali_pmu_unlock(pmu); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PMU: Skipping power down (0x%08X) since Mali is off\n", mask)); ++ ++ return _MALI_OSK_ERR_BUSY; ++ } ++ ++ err = mali_pmu_power_down_internal(pmu, mask); ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ mali_pmu_unlock(pmu); ++ ++ return err; ++} ++ ++_mali_osk_errcode_t mali_pmu_power_up(struct mali_pmu_core *pmu, u32 mask) ++{ ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0 ); ++ ++ /* Make sure we have a valid power domain mask */ ++ if (mask & ~pmu->registered_cores_mask) { ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ mali_pmu_lock(pmu); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PMU: Power up (0x%08X)\n", mask)); ++ ++ pmu->active_cores_mask |= mask; ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ if (!mali_pm_is_power_on()) { ++ /* Don't touch hardware if all of Mali is powered off. */ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ mali_pmu_unlock(pmu); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PMU: Skipping power up (0x%08X) since Mali is off\n", mask)); ++ ++ return _MALI_OSK_ERR_BUSY; ++ } ++ ++ err = mali_pmu_power_up_internal(pmu, mask); ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ mali_pmu_unlock(pmu); ++ ++ return err; ++} ++ ++_mali_osk_errcode_t mali_pmu_power_down_all(struct mali_pmu_core *pmu) ++{ ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0); ++ ++ mali_pmu_lock(pmu); ++ ++ /* Setup the desired defaults in case we were called before mali_pmu_reset() */ ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0); ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_SW_DELAY, pmu->switch_delay); ++ ++ err = mali_pmu_power_down_internal(pmu, pmu->registered_cores_mask); ++ ++ mali_pmu_unlock(pmu); ++ ++ return err; ++} ++ ++_mali_osk_errcode_t mali_pmu_power_up_all(struct mali_pmu_core *pmu) ++{ ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ MALI_DEBUG_ASSERT(pmu->registered_cores_mask != 0); ++ ++ mali_pmu_lock(pmu); ++ ++ /* Setup the desired defaults in case we were called before mali_pmu_reset() */ ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_INT_MASK, 0); ++ mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_SW_DELAY, pmu->switch_delay); ++ ++ err = mali_pmu_power_up_internal(pmu, pmu->active_cores_mask); ++ ++ mali_pmu_unlock(pmu); ++ return err; ++} ++ ++struct mali_pmu_core *mali_pmu_get_global_pmu_core(void) ++{ ++ return mali_global_pmu_core; ++} ++ ++static u32 mali_pmu_detect_mask(void) ++{ ++ int dynamic_config_pp = 0; ++ int dynamic_config_l2 = 0; ++ int i = 0; ++ u32 mask = 0; ++ ++ /* Check if PM domain compatible with actually pp core and l2 cache and collection info about domain */ ++ mask = mali_pmu_get_domain_mask(MALI_GP_DOMAIN_INDEX); ++ ++ for (i = MALI_PP0_DOMAIN_INDEX; i <= MALI_PP7_DOMAIN_INDEX; i++) { ++ mask |= mali_pmu_get_domain_mask(i); ++ ++ if (0x0 != mali_pmu_get_domain_mask(i)) { ++ dynamic_config_pp++; ++ } ++ } ++ ++ for (i = MALI_L20_DOMAIN_INDEX; i <= MALI_L22_DOMAIN_INDEX; i++) { ++ mask |= mali_pmu_get_domain_mask(i); ++ ++ if (0x0 != mali_pmu_get_domain_mask(i)) { ++ dynamic_config_l2++; ++ } ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Mali PMU: mask 0x%x, pp_core %d, l2_core %d \n", mask, dynamic_config_pp, dynamic_config_l2)); ++ ++ return mask; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.h +new file mode 100644 +index 0000000..f16d67a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pmu.h +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_platform.h ++ * Platform specific Mali driver functions ++ */ ++ ++#ifndef __MALI_PMU_H__ ++#define __MALI_PMU_H__ ++ ++#include "mali_osk.h" ++ ++#define MALI_GP_DOMAIN_INDEX 0 ++#define MALI_PP0_DOMAIN_INDEX 1 ++#define MALI_PP1_DOMAIN_INDEX 2 ++#define MALI_PP2_DOMAIN_INDEX 3 ++#define MALI_PP3_DOMAIN_INDEX 4 ++#define MALI_PP4_DOMAIN_INDEX 5 ++#define MALI_PP5_DOMAIN_INDEX 6 ++#define MALI_PP6_DOMAIN_INDEX 7 ++#define MALI_PP7_DOMAIN_INDEX 8 ++#define MALI_L20_DOMAIN_INDEX 9 ++#define MALI_L21_DOMAIN_INDEX 10 ++#define MALI_L22_DOMAIN_INDEX 11 ++ ++#define MALI_MAX_NUMBER_OF_DOMAINS 12 ++ ++/* Record the domain config from the customer or default config */ ++extern u16 mali_pmu_global_domain_config[]; ++ ++static inline u16 mali_pmu_get_domain_mask(u32 index) ++{ ++ MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > index); ++ ++ return mali_pmu_global_domain_config[index]; ++} ++ ++static inline void mali_pmu_set_domain_mask(u32 index, u16 value) ++{ ++ MALI_DEBUG_ASSERT(MALI_MAX_NUMBER_OF_DOMAINS > index); ++ ++ mali_pmu_global_domain_config[index] = value; ++} ++ ++static inline void mali_pmu_copy_domain_mask(void *src, u32 len) ++{ ++ _mali_osk_memcpy(mali_pmu_global_domain_config, src, len); ++} ++ ++struct mali_pmu_core; ++ ++/** @brief Initialisation of MALI PMU ++ * ++ * This is called from entry point of the driver in order to create and intialize the PMU resource ++ * ++ * @param resource it will be a pointer to a PMU resource ++ * @param number_of_pp_cores Number of found PP resources in configuration ++ * @param number_of_l2_caches Number of found L2 cache resources in configuration ++ * @return The created PMU object, or NULL in case of failure. ++ */ ++struct mali_pmu_core *mali_pmu_create(_mali_osk_resource_t *resource); ++ ++/** @brief It deallocates the PMU resource ++ * ++ * This is called on the exit of the driver to terminate the PMU resource ++ * ++ * @param pmu Pointer to PMU core object to delete ++ */ ++void mali_pmu_delete(struct mali_pmu_core *pmu); ++ ++/** @brief Reset PMU core ++ * ++ * @param pmu Pointer to PMU core object to reset ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t mali_pmu_reset(struct mali_pmu_core *pmu); ++ ++/** @brief MALI GPU power down using MALI in-built PMU ++ * ++ * Called to power down the specified cores. The mask will be saved so that \a ++ * mali_pmu_power_up_all will bring the PMU back to the previous state set with ++ * this function or \a mali_pmu_power_up. ++ * ++ * @param pmu Pointer to PMU core object to power down ++ * @param mask Mask specifying which power domains to power down ++ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. ++ */ ++_mali_osk_errcode_t mali_pmu_power_down(struct mali_pmu_core *pmu, u32 mask); ++ ++/** @brief MALI GPU power up using MALI in-built PMU ++ * ++ * Called to power up the specified cores. The mask will be saved so that \a ++ * mali_pmu_power_up_all will bring the PMU back to the previous state set with ++ * this function or \a mali_pmu_power_down. ++ * ++ * @param pmu Pointer to PMU core object to power up ++ * @param mask Mask specifying which power domains to power up ++ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. ++ */ ++_mali_osk_errcode_t mali_pmu_power_up(struct mali_pmu_core *pmu, u32 mask); ++ ++/** @brief MALI GPU power down using MALI in-built PMU ++ * ++ * called to power down all cores ++ * ++ * @param pmu Pointer to PMU core object to power down ++ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. ++ */ ++_mali_osk_errcode_t mali_pmu_power_down_all(struct mali_pmu_core *pmu); ++ ++/** @brief MALI GPU power up using MALI in-built PMU ++ * ++ * called to power up all cores ++ * ++ * @param pmu Pointer to PMU core object to power up ++ * @return _MALI_OSK_ERR_OK on success otherwise, a suitable _mali_osk_errcode_t error. ++ */ ++_mali_osk_errcode_t mali_pmu_power_up_all(struct mali_pmu_core *pmu); ++ ++/** @brief Retrieves the Mali PMU core object (if any) ++ * ++ * @return The Mali PMU object, or NULL if no PMU exists. ++ */ ++struct mali_pmu_core *mali_pmu_get_global_pmu_core(void); ++ ++#endif /* __MALI_PMU_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.c +new file mode 100644 +index 0000000..0f48137 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.c +@@ -0,0 +1,573 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_pp_job.h" ++#include "mali_pp.h" ++#include "mali_hw_core.h" ++#include "mali_group.h" ++#include "regs/mali_200_regs.h" ++#include "mali_kernel_common.h" ++#include "mali_kernel_core.h" ++#include "mali_dma.h" ++#if defined(CONFIG_MALI400_PROFILING) ++#include "mali_osk_profiling.h" ++#endif ++ ++/* Number of frame registers on Mali-200 */ ++#define MALI_PP_MALI200_NUM_FRAME_REGISTERS ((0x04C/4)+1) ++/* Number of frame registers on Mali-300 and later */ ++#define MALI_PP_MALI400_NUM_FRAME_REGISTERS ((0x058/4)+1) ++ ++static struct mali_pp_core* mali_global_pp_cores[MALI_MAX_NUMBER_OF_PP_CORES] = { NULL }; ++static u32 mali_global_num_pp_cores = 0; ++ ++/* Interrupt handlers */ ++static void mali_pp_irq_probe_trigger(void *data); ++static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data); ++ ++struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t *resource, struct mali_group *group, mali_bool is_virtual, u32 bcast_id) ++{ ++ struct mali_pp_core* core = NULL; ++ ++ MALI_DEBUG_PRINT(2, ("Mali PP: Creating Mali PP core: %s\n", resource->description)); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Base address of PP core: 0x%x\n", resource->base)); ++ ++ if (mali_global_num_pp_cores >= MALI_MAX_NUMBER_OF_PP_CORES) { ++ MALI_PRINT_ERROR(("Mali PP: Too many PP core objects created\n")); ++ return NULL; ++ } ++ ++ core = _mali_osk_malloc(sizeof(struct mali_pp_core)); ++ if (NULL != core) { ++ core->core_id = mali_global_num_pp_cores; ++ core->bcast_id = bcast_id; ++ ++ if (_MALI_OSK_ERR_OK == mali_hw_core_create(&core->hw_core, resource, MALI200_REG_SIZEOF_REGISTER_BANK)) { ++ _mali_osk_errcode_t ret; ++ ++ if (!is_virtual) { ++ ret = mali_pp_reset(core); ++ } else { ++ ret = _MALI_OSK_ERR_OK; ++ } ++ ++ if (_MALI_OSK_ERR_OK == ret) { ++ ret = mali_group_add_pp_core(group, core); ++ if (_MALI_OSK_ERR_OK == ret) { ++ /* Setup IRQ handlers (which will do IRQ probing if needed) */ ++ MALI_DEBUG_ASSERT(!is_virtual || -1 != resource->irq); ++ ++ core->irq = _mali_osk_irq_init(resource->irq, ++ mali_group_upper_half_pp, ++ group, ++ mali_pp_irq_probe_trigger, ++ mali_pp_irq_probe_ack, ++ core, ++ resource->description); ++ if (NULL != core->irq) { ++ mali_global_pp_cores[mali_global_num_pp_cores] = core; ++ mali_global_num_pp_cores++; ++ ++ return core; ++ } else { ++ MALI_PRINT_ERROR(("Mali PP: Failed to setup interrupt handlers for PP core %s\n", core->hw_core.description)); ++ } ++ mali_group_remove_pp_core(group); ++ } else { ++ MALI_PRINT_ERROR(("Mali PP: Failed to add core %s to group\n", core->hw_core.description)); ++ } ++ } ++ mali_hw_core_delete(&core->hw_core); ++ } ++ ++ _mali_osk_free(core); ++ } else { ++ MALI_PRINT_ERROR(("Mali PP: Failed to allocate memory for PP core\n")); ++ } ++ ++ return NULL; ++} ++ ++void mali_pp_delete(struct mali_pp_core *core) ++{ ++ u32 i; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ _mali_osk_irq_term(core->irq); ++ mali_hw_core_delete(&core->hw_core); ++ ++ /* Remove core from global list */ ++ for (i = 0; i < mali_global_num_pp_cores; i++) { ++ if (mali_global_pp_cores[i] == core) { ++ mali_global_pp_cores[i] = NULL; ++ mali_global_num_pp_cores--; ++ ++ if (i != mali_global_num_pp_cores) { ++ /* We removed a PP core from the middle of the array -- move the last ++ * PP core to the current position to close the gap */ ++ mali_global_pp_cores[i] = mali_global_pp_cores[mali_global_num_pp_cores]; ++ mali_global_pp_cores[mali_global_num_pp_cores] = NULL; ++ } ++ ++ break; ++ } ++ } ++ ++ _mali_osk_free(core); ++} ++ ++void mali_pp_stop_bus(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ /* Will only send the stop bus command, and not wait for it to complete */ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_STOP_BUS); ++} ++ ++_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core) ++{ ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ /* Send the stop bus command. */ ++ mali_pp_stop_bus(core); ++ ++ /* Wait for bus to be stopped */ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ if (mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) & MALI200_REG_VAL_STATUS_BUS_STOPPED) ++ break; ++ } ++ ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Mali PP: Failed to stop bus on %s. Status: 0x%08x\n", core->hw_core.description, mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++/* Frame register reset values. ++ * Taken from the Mali400 TRM, 3.6. Pixel processor control register summary */ ++static const u32 mali_frame_registers_reset_values[_MALI_PP_MAX_FRAME_REGISTERS] = { ++ 0x0, /* Renderer List Address Register */ ++ 0x0, /* Renderer State Word Base Address Register */ ++ 0x0, /* Renderer Vertex Base Register */ ++ 0x2, /* Feature Enable Register */ ++ 0x0, /* Z Clear Value Register */ ++ 0x0, /* Stencil Clear Value Register */ ++ 0x0, /* ABGR Clear Value 0 Register */ ++ 0x0, /* ABGR Clear Value 1 Register */ ++ 0x0, /* ABGR Clear Value 2 Register */ ++ 0x0, /* ABGR Clear Value 3 Register */ ++ 0x0, /* Bounding Box Left Right Register */ ++ 0x0, /* Bounding Box Bottom Register */ ++ 0x0, /* FS Stack Address Register */ ++ 0x0, /* FS Stack Size and Initial Value Register */ ++ 0x0, /* Reserved */ ++ 0x0, /* Reserved */ ++ 0x0, /* Origin Offset X Register */ ++ 0x0, /* Origin Offset Y Register */ ++ 0x75, /* Subpixel Specifier Register */ ++ 0x0, /* Tiebreak mode Register */ ++ 0x0, /* Polygon List Format Register */ ++ 0x0, /* Scaling Register */ ++ 0x0 /* Tilebuffer configuration Register */ ++}; ++ ++/* WBx register reset values */ ++static const u32 mali_wb_registers_reset_values[_MALI_PP_MAX_WB_REGISTERS] = { ++ 0x0, /* WBx Source Select Register */ ++ 0x0, /* WBx Target Address Register */ ++ 0x0, /* WBx Target Pixel Format Register */ ++ 0x0, /* WBx Target AA Format Register */ ++ 0x0, /* WBx Target Layout */ ++ 0x0, /* WBx Target Scanline Length */ ++ 0x0, /* WBx Target Flags Register */ ++ 0x0, /* WBx MRT Enable Register */ ++ 0x0, /* WBx MRT Offset Register */ ++ 0x0, /* WBx Global Test Enable Register */ ++ 0x0, /* WBx Global Test Reference Value Register */ ++ 0x0 /* WBx Global Test Compare Function Register */ ++}; ++ ++/* Performance Counter 0 Enable Register reset value */ ++static const u32 mali_perf_cnt_enable_reset_value = 0; ++ ++_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core) ++{ ++ /* Bus must be stopped before calling this function */ ++ const u32 reset_invalid_value = 0xC0FFE000; ++ const u32 reset_check_value = 0xC01A0000; ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Hard reset of core %s\n", core->hw_core.description)); ++ ++ /* Set register to a bogus value. The register will be used to detect when reset is complete */ ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_invalid_value); ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); ++ ++ /* Force core to reset */ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET); ++ ++ /* Wait for reset to be complete */ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, reset_check_value); ++ if (reset_check_value == mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW)) { ++ break; ++ } ++ } ++ ++ if (MALI_REG_POLL_COUNT_FAST == i) { ++ MALI_PRINT_ERROR(("Mali PP: The hard reset loop didn't work, unable to recover\n")); ++ } ++ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW, 0x00000000); /* set it back to the default */ ++ /* Re-enable interrupts */ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_pp_reset_async(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP: Reset of core %s\n", core->hw_core.description)); ++ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, 0); /* disable the IRQs */ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_MASK_ALL); ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET); ++} ++ ++_mali_osk_errcode_t mali_pp_reset_wait(struct mali_pp_core *core) ++{ ++ int i; ++ u32 rawstat = 0; ++ ++ for (i = 0; i < MALI_REG_POLL_COUNT_FAST; i++) { ++ if (!(mali_pp_read_status(core) & MALI200_REG_VAL_STATUS_RENDERING_ACTIVE)) { ++ rawstat = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT); ++ if (rawstat == MALI400PP_REG_VAL_IRQ_RESET_COMPLETED) { ++ break; ++ } ++ } ++ } ++ ++ if (i == MALI_REG_POLL_COUNT_FAST) { ++ MALI_PRINT_ERROR(("Mali PP: Failed to reset core %s, rawstat: 0x%08x\n", ++ core->hw_core.description, rawstat)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Re-enable interrupts */ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_MASK_ALL); ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core) ++{ ++ mali_pp_reset_async(core); ++ return mali_pp_reset_wait(core); ++} ++ ++void mali_pp_job_dma_cmd_prepare(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job, ++ mali_bool restart_virtual, mali_dma_cmd_buf *buf) ++{ ++ u32 relative_address; ++ u32 start_index; ++ u32 nr_of_regs; ++ u32 *frame_registers = mali_pp_job_get_frame_registers(job); ++ u32 *wb0_registers = mali_pp_job_get_wb0_registers(job); ++ u32 *wb1_registers = mali_pp_job_get_wb1_registers(job); ++ u32 *wb2_registers = mali_pp_job_get_wb2_registers(job); ++ u32 counter_src0 = mali_pp_job_get_perf_counter_src0(job, sub_job); ++ u32 counter_src1 = mali_pp_job_get_perf_counter_src1(job, sub_job); ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ /* Write frame registers */ ++ ++ /* ++ * There are two frame registers which are different for each sub job: ++ * 1. The Renderer List Address Register (MALI200_REG_ADDR_FRAME) ++ * 2. The FS Stack Address Register (MALI200_REG_ADDR_STACK) ++ */ ++ mali_dma_write_conditional(buf, &core->hw_core, MALI200_REG_ADDR_FRAME, mali_pp_job_get_addr_frame(job, sub_job), mali_frame_registers_reset_values[MALI200_REG_ADDR_FRAME / sizeof(u32)]); ++ ++ /* For virtual jobs, the stack address shouldn't be broadcast but written individually */ ++ if (!mali_pp_job_is_virtual(job) || restart_virtual) { ++ mali_dma_write_conditional(buf, &core->hw_core, MALI200_REG_ADDR_STACK, mali_pp_job_get_addr_stack(job, sub_job), mali_frame_registers_reset_values[MALI200_REG_ADDR_STACK / sizeof(u32)]); ++ } ++ ++ /* Write registers between MALI200_REG_ADDR_FRAME and MALI200_REG_ADDR_STACK */ ++ relative_address = MALI200_REG_ADDR_RSW; ++ start_index = MALI200_REG_ADDR_RSW / sizeof(u32); ++ nr_of_regs = (MALI200_REG_ADDR_STACK - MALI200_REG_ADDR_RSW) / sizeof(u32); ++ ++ mali_dma_write_array_conditional(buf, &core->hw_core, ++ relative_address, &frame_registers[start_index], ++ nr_of_regs, &mali_frame_registers_reset_values[start_index]); ++ ++ /* MALI200_REG_ADDR_STACK_SIZE */ ++ relative_address = MALI200_REG_ADDR_STACK_SIZE; ++ start_index = MALI200_REG_ADDR_STACK_SIZE / sizeof(u32); ++ ++ mali_dma_write_conditional(buf, &core->hw_core, ++ relative_address, frame_registers[start_index], ++ mali_frame_registers_reset_values[start_index]); ++ ++ /* Skip 2 reserved registers */ ++ ++ /* Write remaining registers */ ++ relative_address = MALI200_REG_ADDR_ORIGIN_OFFSET_X; ++ start_index = MALI200_REG_ADDR_ORIGIN_OFFSET_X / sizeof(u32); ++ nr_of_regs = MALI_PP_MALI400_NUM_FRAME_REGISTERS - MALI200_REG_ADDR_ORIGIN_OFFSET_X / sizeof(u32); ++ ++ mali_dma_write_array_conditional(buf, &core->hw_core, ++ relative_address, &frame_registers[start_index], ++ nr_of_regs, &mali_frame_registers_reset_values[start_index]); ++ ++ /* Write WBx registers */ ++ if (wb0_registers[0]) { /* M200_WB0_REG_SOURCE_SELECT register */ ++ mali_dma_write_array_conditional(buf, &core->hw_core, MALI200_REG_ADDR_WB0, wb0_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (wb1_registers[0]) { /* M200_WB1_REG_SOURCE_SELECT register */ ++ mali_dma_write_array_conditional(buf, &core->hw_core, MALI200_REG_ADDR_WB1, wb1_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (wb2_registers[0]) { /* M200_WB2_REG_SOURCE_SELECT register */ ++ mali_dma_write_array_conditional(buf, &core->hw_core, MALI200_REG_ADDR_WB2, wb2_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src0) { ++ mali_dma_write(buf, &core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, counter_src0); ++ mali_dma_write_conditional(buf, &core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE, mali_perf_cnt_enable_reset_value); ++ } ++ if (MALI_HW_CORE_NO_COUNTER != counter_src1) { ++ mali_dma_write(buf, &core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, counter_src1); ++ mali_dma_write_conditional(buf, &core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE, mali_perf_cnt_enable_reset_value); ++ } ++ ++ /* This is the command that starts the core. */ ++ mali_dma_write(buf, &core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); ++} ++ ++void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job, mali_bool restart_virtual) ++{ ++ u32 relative_address; ++ u32 start_index; ++ u32 nr_of_regs; ++ u32 *frame_registers = mali_pp_job_get_frame_registers(job); ++ u32 *wb0_registers = mali_pp_job_get_wb0_registers(job); ++ u32 *wb1_registers = mali_pp_job_get_wb1_registers(job); ++ u32 *wb2_registers = mali_pp_job_get_wb2_registers(job); ++ u32 counter_src0 = mali_pp_job_get_perf_counter_src0(job, sub_job); ++ u32 counter_src1 = mali_pp_job_get_perf_counter_src1(job, sub_job); ++ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ /* Write frame registers */ ++ ++ /* ++ * There are two frame registers which are different for each sub job: ++ * 1. The Renderer List Address Register (MALI200_REG_ADDR_FRAME) ++ * 2. The FS Stack Address Register (MALI200_REG_ADDR_STACK) ++ */ ++ mali_hw_core_register_write_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_FRAME, mali_pp_job_get_addr_frame(job, sub_job), mali_frame_registers_reset_values[MALI200_REG_ADDR_FRAME / sizeof(u32)]); ++ ++ /* For virtual jobs, the stack address shouldn't be broadcast but written individually */ ++ if (!mali_pp_job_is_virtual(job) || restart_virtual) { ++ mali_hw_core_register_write_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_STACK, mali_pp_job_get_addr_stack(job, sub_job), mali_frame_registers_reset_values[MALI200_REG_ADDR_STACK / sizeof(u32)]); ++ } ++ ++ /* Write registers between MALI200_REG_ADDR_FRAME and MALI200_REG_ADDR_STACK */ ++ relative_address = MALI200_REG_ADDR_RSW; ++ start_index = MALI200_REG_ADDR_RSW / sizeof(u32); ++ nr_of_regs = (MALI200_REG_ADDR_STACK - MALI200_REG_ADDR_RSW) / sizeof(u32); ++ ++ mali_hw_core_register_write_array_relaxed_conditional(&core->hw_core, ++ relative_address, &frame_registers[start_index], ++ nr_of_regs, &mali_frame_registers_reset_values[start_index]); ++ ++ /* MALI200_REG_ADDR_STACK_SIZE */ ++ relative_address = MALI200_REG_ADDR_STACK_SIZE; ++ start_index = MALI200_REG_ADDR_STACK_SIZE / sizeof(u32); ++ ++ mali_hw_core_register_write_relaxed_conditional(&core->hw_core, ++ relative_address, frame_registers[start_index], ++ mali_frame_registers_reset_values[start_index]); ++ ++ /* Skip 2 reserved registers */ ++ ++ /* Write remaining registers */ ++ relative_address = MALI200_REG_ADDR_ORIGIN_OFFSET_X; ++ start_index = MALI200_REG_ADDR_ORIGIN_OFFSET_X / sizeof(u32); ++ nr_of_regs = MALI_PP_MALI400_NUM_FRAME_REGISTERS - MALI200_REG_ADDR_ORIGIN_OFFSET_X / sizeof(u32); ++ ++ mali_hw_core_register_write_array_relaxed_conditional(&core->hw_core, ++ relative_address, &frame_registers[start_index], ++ nr_of_regs, &mali_frame_registers_reset_values[start_index]); ++ ++ /* Write WBx registers */ ++ if (wb0_registers[0]) { /* M200_WB0_REG_SOURCE_SELECT register */ ++ mali_hw_core_register_write_array_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_WB0, wb0_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (wb1_registers[0]) { /* M200_WB1_REG_SOURCE_SELECT register */ ++ mali_hw_core_register_write_array_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_WB1, wb1_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (wb2_registers[0]) { /* M200_WB2_REG_SOURCE_SELECT register */ ++ mali_hw_core_register_write_array_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_WB2, wb2_registers, _MALI_PP_MAX_WB_REGISTERS, mali_wb_registers_reset_values); ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src0) { ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC, counter_src0); ++ mali_hw_core_register_write_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE, mali_perf_cnt_enable_reset_value); ++ } ++ if (MALI_HW_CORE_NO_COUNTER != counter_src1) { ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC, counter_src1); ++ mali_hw_core_register_write_relaxed_conditional(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE, MALI200_REG_VAL_PERF_CNT_ENABLE, mali_perf_cnt_enable_reset_value); ++ } ++ ++#ifdef CONFIG_MALI400_HEATMAPS_ENABLED ++ if(job->uargs.perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_HEATMAP_ENABLE) { ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_PERFMON_CONTR, ((job->uargs.tilesx & 0x3FF) << 16) | 1); ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_PERFMON_BASE, job->uargs.heatmap_mem & 0xFFFFFFF8); ++ } ++#endif /* CONFIG_MALI400_HEATMAPS_ENABLED */ ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP: Starting job 0x%08X part %u/%u on PP core %s\n", job, sub_job + 1, mali_pp_job_get_sub_job_count(job), core->hw_core.description)); ++ ++ /* Adding barrier to make sure all rester writes are finished */ ++ _mali_osk_write_mem_barrier(); ++ ++ /* This is the command that starts the core. */ ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_MGMT_CTRL_MGMT, MALI200_REG_VAL_CTRL_MGMT_START_RENDERING); ++ ++ /* Adding barrier to make sure previous rester writes is finished */ ++ _mali_osk_write_mem_barrier(); ++} ++ ++u32 mali_pp_core_get_version(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION); ++} ++ ++struct mali_pp_core* mali_pp_get_global_pp_core(u32 index) ++{ ++ if (mali_global_num_pp_cores > index) { ++ return mali_global_pp_cores[index]; ++ } ++ ++ return NULL; ++} ++ ++u32 mali_pp_get_glob_num_pp_cores(void) ++{ ++ return mali_global_num_pp_cores; ++} ++ ++/* ------------- interrupt handling below ------------------ */ ++static void mali_pp_irq_probe_trigger(void *data) ++{ ++ struct mali_pp_core *core = (struct mali_pp_core *)data; ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT, MALI200_REG_VAL_IRQ_FORCE_HANG); ++ _mali_osk_mem_barrier(); ++} ++ ++static _mali_osk_errcode_t mali_pp_irq_probe_ack(void *data) ++{ ++ struct mali_pp_core *core = (struct mali_pp_core *)data; ++ u32 irq_readout; ++ ++ irq_readout = mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); ++ if (MALI200_REG_VAL_IRQ_FORCE_HANG & irq_readout) { ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_FORCE_HANG); ++ _mali_osk_mem_barrier(); ++ return _MALI_OSK_ERR_OK; ++ } ++ ++ return _MALI_OSK_ERR_FAULT; ++} ++ ++ ++#if 0 ++static void mali_pp_print_registers(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_VERSION = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_VERSION))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_RAWSTAT = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_MASK = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_INT_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC))); ++ MALI_DEBUG_PRINT(2, ("Mali PP: Register MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x%08X\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE))); ++} ++#endif ++ ++#if 0 ++void mali_pp_print_state(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_PRINT(2, ("Mali PP: State: 0x%08x\n", mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS) )); ++} ++#endif ++ ++void mali_pp_update_performance_counters(struct mali_pp_core *parent, struct mali_pp_core *child, struct mali_pp_job *job, u32 subjob) ++{ ++ u32 val0 = 0; ++ u32 val1 = 0; ++ u32 counter_src0 = mali_pp_job_get_perf_counter_src0(job, subjob); ++ u32 counter_src1 = mali_pp_job_get_perf_counter_src1(job, subjob); ++#if defined(CONFIG_MALI400_PROFILING) ++ int counter_index = COUNTER_FP_0_C0 + (2 * child->core_id); ++#endif ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src0) { ++ val0 = mali_hw_core_register_read(&child->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE); ++ mali_pp_job_set_perf_counter_value0(job, subjob, val0); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_report_hw_counter(counter_index, val0); ++#endif ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER != counter_src1) { ++ val1 = mali_hw_core_register_read(&child->hw_core, MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE); ++ mali_pp_job_set_perf_counter_value1(job, subjob, val1); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ _mali_osk_profiling_report_hw_counter(counter_index + 1, val1); ++#endif ++ } ++} ++ ++#if MALI_STATE_TRACKING ++u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size) ++{ ++ int n = 0; ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "\tPP #%d: %s\n", core->core_id, core->hw_core.description); ++ ++ return n; ++} ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.h +new file mode 100644 +index 0000000..a7d5956 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp.h +@@ -0,0 +1,131 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PP_H__ ++#define __MALI_PP_H__ ++ ++#include "mali_osk.h" ++#include "mali_pp_job.h" ++#include "mali_hw_core.h" ++#include "mali_dma.h" ++ ++struct mali_group; ++ ++#define MALI_MAX_NUMBER_OF_PP_CORES 9 ++ ++/** ++ * Definition of the PP core struct ++ * Used to track a PP core in the system. ++ */ ++struct mali_pp_core { ++ struct mali_hw_core hw_core; /**< Common for all HW cores */ ++ _mali_osk_irq_t *irq; /**< IRQ handler */ ++ u32 core_id; /**< Unique core ID */ ++ u32 bcast_id; /**< The "flag" value used by the Mali-450 broadcast and DLBU unit */ ++}; ++ ++_mali_osk_errcode_t mali_pp_initialize(void); ++void mali_pp_terminate(void); ++ ++struct mali_pp_core *mali_pp_create(const _mali_osk_resource_t * resource, struct mali_group *group, mali_bool is_virtual, u32 bcast_id); ++void mali_pp_delete(struct mali_pp_core *core); ++ ++void mali_pp_stop_bus(struct mali_pp_core *core); ++_mali_osk_errcode_t mali_pp_stop_bus_wait(struct mali_pp_core *core); ++void mali_pp_reset_async(struct mali_pp_core *core); ++_mali_osk_errcode_t mali_pp_reset_wait(struct mali_pp_core *core); ++_mali_osk_errcode_t mali_pp_reset(struct mali_pp_core *core); ++_mali_osk_errcode_t mali_pp_hard_reset(struct mali_pp_core *core); ++ ++void mali_pp_job_start(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job, mali_bool restart_virtual); ++ ++/** ++ * @brief Add commands to DMA command buffer to start PP job on core. ++ */ ++void mali_pp_job_dma_cmd_prepare(struct mali_pp_core *core, struct mali_pp_job *job, u32 sub_job, ++ mali_bool restart_virtual, mali_dma_cmd_buf *buf); ++ ++u32 mali_pp_core_get_version(struct mali_pp_core *core); ++ ++MALI_STATIC_INLINE u32 mali_pp_core_get_id(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ return core->core_id; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_core_get_bcast_id(struct mali_pp_core *core) ++{ ++ MALI_DEBUG_ASSERT_POINTER(core); ++ return core->bcast_id; ++} ++ ++struct mali_pp_core* mali_pp_get_global_pp_core(u32 index); ++u32 mali_pp_get_glob_num_pp_cores(void); ++ ++/* Debug */ ++u32 mali_pp_dump_state(struct mali_pp_core *core, char *buf, u32 size); ++ ++/** ++ * Put instrumented HW counters from the core(s) to the job object (if enabled) ++ * ++ * parent and child is always the same, except for virtual jobs on Mali-450. ++ * In this case, the counters will be enabled on the virtual core (parent), ++ * but values need to be read from the child cores. ++ * ++ * @param parent The core used to see if the counters was enabled ++ * @param child The core to actually read the values from ++ * @job Job object to update with counter values (if enabled) ++ * @subjob Which subjob the counters are applicable for (core ID for virtual jobs) ++ */ ++void mali_pp_update_performance_counters(struct mali_pp_core *parent, struct mali_pp_core *child, struct mali_pp_job *job, u32 subjob); ++ ++MALI_STATIC_INLINE const char *mali_pp_get_hw_core_desc(struct mali_pp_core *core) ++{ ++ return core->hw_core.description; ++} ++ ++/*** Register reading/writing functions ***/ ++MALI_STATIC_INLINE u32 mali_pp_get_int_stat(struct mali_pp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_STATUS); ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_read_rawstat(struct mali_pp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_RAWSTAT) & MALI200_REG_VAL_IRQ_MASK_USED; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_read_status(struct mali_pp_core *core) ++{ ++ return mali_hw_core_register_read(&core->hw_core, MALI200_REG_ADDR_MGMT_STATUS); ++} ++ ++MALI_STATIC_INLINE void mali_pp_mask_all_interrupts(struct mali_pp_core *core) ++{ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_NONE); ++} ++ ++MALI_STATIC_INLINE void mali_pp_clear_hang_interrupt(struct mali_pp_core *core) ++{ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_CLEAR, MALI200_REG_VAL_IRQ_HANG); ++} ++ ++MALI_STATIC_INLINE void mali_pp_enable_interrupts(struct mali_pp_core *core) ++{ ++ mali_hw_core_register_write(&core->hw_core, MALI200_REG_ADDR_MGMT_INT_MASK, MALI200_REG_VAL_IRQ_MASK_USED); ++} ++ ++MALI_STATIC_INLINE void mali_pp_write_addr_stack(struct mali_pp_core *core, struct mali_pp_job *job) ++{ ++ u32 addr = mali_pp_job_get_addr_stack(job, core->core_id); ++ mali_hw_core_register_write_relaxed(&core->hw_core, MALI200_REG_ADDR_STACK, addr); ++} ++ ++#endif /* __MALI_PP_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.c +new file mode 100644 +index 0000000..af9cb54 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.c +@@ -0,0 +1,278 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_pp.h" ++#include "mali_pp_job.h" ++#include "mali_dma.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_kernel_common.h" ++#include "mali_uk_types.h" ++#include "mali_pp_scheduler.h" ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++#include "linux/mali_memory_dma_buf.h" ++#endif ++ ++static u32 pp_counter_src0 = MALI_HW_CORE_NO_COUNTER; /**< Performance counter 0, MALI_HW_CORE_NO_COUNTER for disabled */ ++static u32 pp_counter_src1 = MALI_HW_CORE_NO_COUNTER; /**< Performance counter 1, MALI_HW_CORE_NO_COUNTER for disabled */ ++static _mali_osk_atomic_t pp_counter_per_sub_job_count; /**< Number of values in the two arrays which is != MALI_HW_CORE_NO_COUNTER */ ++static u32 pp_counter_per_sub_job_src0[_MALI_PP_MAX_SUB_JOBS] = { MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER }; ++static u32 pp_counter_per_sub_job_src1[_MALI_PP_MAX_SUB_JOBS] = { MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER, MALI_HW_CORE_NO_COUNTER }; ++ ++void mali_pp_job_initialize(void) ++{ ++ _mali_osk_atomic_init(&pp_counter_per_sub_job_count, 0); ++} ++ ++void mali_pp_job_terminate(void) ++{ ++ _mali_osk_atomic_term(&pp_counter_per_sub_job_count); ++} ++ ++struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *uargs, u32 id) ++{ ++ struct mali_pp_job *job; ++ u32 perf_counter_flag; ++ ++ job = _mali_osk_calloc(1, sizeof(struct mali_pp_job)); ++ if (NULL != job) { ++ if (0 != _mali_osk_copy_from_user(&job->uargs, uargs, sizeof(_mali_uk_pp_start_job_s))) { ++ goto fail; ++ } ++ ++ if (job->uargs.num_cores > _MALI_PP_MAX_SUB_JOBS) { ++ MALI_PRINT_ERROR(("Mali PP job: Too many sub jobs specified in job object\n")); ++ goto fail; ++ } ++ ++ if (!mali_pp_job_use_no_notification(job)) { ++ job->finished_notification = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_FINISHED, sizeof(_mali_uk_pp_job_finished_s)); ++ if (NULL == job->finished_notification) goto fail; ++ } ++ ++ perf_counter_flag = mali_pp_job_get_perf_counter_flag(job); ++ ++ /* case when no counters came from user space ++ * so pass the debugfs / DS-5 provided global ones to the job object */ ++ if (!((perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE) || ++ (perf_counter_flag & _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE))) { ++ u32 sub_job_count = _mali_osk_atomic_read(&pp_counter_per_sub_job_count); ++ ++ /* These counters apply for all virtual jobs, and where no per sub job counter is specified */ ++ job->uargs.perf_counter_src0 = pp_counter_src0; ++ job->uargs.perf_counter_src1 = pp_counter_src1; ++ ++ /* We only copy the per sub job array if it is enabled with at least one counter */ ++ if (0 < sub_job_count) { ++ job->perf_counter_per_sub_job_count = sub_job_count; ++ _mali_osk_memcpy(job->perf_counter_per_sub_job_src0, pp_counter_per_sub_job_src0, sizeof(pp_counter_per_sub_job_src0)); ++ _mali_osk_memcpy(job->perf_counter_per_sub_job_src1, pp_counter_per_sub_job_src1, sizeof(pp_counter_per_sub_job_src1)); ++ } ++ } ++ ++ _mali_osk_list_init(&job->list); ++ job->session = session; ++ _mali_osk_list_init(&job->session_list); ++ job->id = id; ++ ++ job->sub_jobs_num = job->uargs.num_cores ? job->uargs.num_cores : 1; ++ job->pid = _mali_osk_get_pid(); ++ job->tid = _mali_osk_get_tid(); ++ ++ job->num_memory_cookies = job->uargs.num_memory_cookies; ++ if (job->num_memory_cookies > 0) { ++ u32 size; ++ ++ if (job->uargs.num_memory_cookies > session->descriptor_mapping->current_nr_mappings) { ++ MALI_PRINT_ERROR(("Mali PP job: Too many memory cookies specified in job object\n")); ++ goto fail; ++ } ++ ++ size = sizeof(*job->uargs.memory_cookies) * job->num_memory_cookies; ++ ++ job->memory_cookies = _mali_osk_malloc(size); ++ if (NULL == job->memory_cookies) { ++ MALI_PRINT_ERROR(("Mali PP job: Failed to allocate %d bytes of memory cookies!\n", size)); ++ goto fail; ++ } ++ ++ if (0 != _mali_osk_copy_from_user(job->memory_cookies, job->uargs.memory_cookies, size)) { ++ MALI_PRINT_ERROR(("Mali PP job: Failed to copy %d bytes of memory cookies from user!\n", size)); ++ goto fail; ++ } ++ ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++ job->num_dma_bufs = job->num_memory_cookies; ++ job->dma_bufs = _mali_osk_calloc(job->num_dma_bufs, sizeof(struct mali_dma_buf_attachment *)); ++ if (NULL == job->dma_bufs) { ++ MALI_PRINT_ERROR(("Mali PP job: Failed to allocate dma_bufs array!\n")); ++ goto fail; ++ } ++#endif ++ } ++ ++ /* Prepare DMA command buffer to start job, if it is virtual. */ ++ if (mali_pp_job_is_virtual(job)) { ++ struct mali_pp_core *core; ++ _mali_osk_errcode_t err = mali_dma_get_cmd_buf(&job->dma_cmd_buf); ++ ++ if (_MALI_OSK_ERR_OK != err) { ++ MALI_PRINT_ERROR(("Mali PP job: Failed to allocate DMA command buffer\n")); ++ goto fail; ++ } ++ ++ core = mali_pp_scheduler_get_virtual_pp(); ++ MALI_DEBUG_ASSERT_POINTER(core); ++ ++ mali_pp_job_dma_cmd_prepare(core, job, 0, MALI_FALSE, &job->dma_cmd_buf); ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_pp_job_check(job)) { ++ /* Not a valid job. */ ++ goto fail; ++ } ++ ++ mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_PP, NULL, job); ++ mali_timeline_fence_copy_uk_fence(&(job->tracker.fence), &(job->uargs.fence)); ++ ++ return job; ++ } ++ ++fail: ++ if (NULL != job) { ++ mali_pp_job_delete(job); ++ } ++ ++ return NULL; ++} ++ ++void mali_pp_job_delete(struct mali_pp_job *job) ++{ ++ mali_dma_put_cmd_buf(&job->dma_cmd_buf); ++ if (NULL != job->finished_notification) { ++ _mali_osk_notification_delete(job->finished_notification); ++ } ++ ++ _mali_osk_free(job->memory_cookies); ++ ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++ /* Unmap buffers attached to job */ ++ if (0 < job->num_dma_bufs) { ++ mali_dma_buf_unmap_job(job); ++ } ++ ++ _mali_osk_free(job->dma_bufs); ++#endif /* CONFIG_DMA_SHARED_BUFFER */ ++ ++ _mali_osk_free(job); ++} ++ ++u32 mali_pp_job_get_perf_counter_src0(struct mali_pp_job *job, u32 sub_job) ++{ ++ /* Virtual jobs always use the global job counter (or if there are per sub job counters at all) */ ++ if (mali_pp_job_is_virtual(job) || 0 == job->perf_counter_per_sub_job_count) { ++ return job->uargs.perf_counter_src0; ++ } ++ ++ /* Use per sub job counter if enabled... */ ++ if (MALI_HW_CORE_NO_COUNTER != job->perf_counter_per_sub_job_src0[sub_job]) { ++ return job->perf_counter_per_sub_job_src0[sub_job]; ++ } ++ ++ /* ...else default to global job counter */ ++ return job->uargs.perf_counter_src0; ++} ++ ++u32 mali_pp_job_get_perf_counter_src1(struct mali_pp_job *job, u32 sub_job) ++{ ++ /* Virtual jobs always use the global job counter (or if there are per sub job counters at all) */ ++ if (mali_pp_job_is_virtual(job) || 0 == job->perf_counter_per_sub_job_count) { ++ /* Virtual jobs always use the global job counter */ ++ return job->uargs.perf_counter_src1; ++ } ++ ++ /* Use per sub job counter if enabled... */ ++ if (MALI_HW_CORE_NO_COUNTER != job->perf_counter_per_sub_job_src1[sub_job]) { ++ return job->perf_counter_per_sub_job_src1[sub_job]; ++ } ++ ++ /* ...else default to global job counter */ ++ return job->uargs.perf_counter_src1; ++} ++ ++void mali_pp_job_set_pp_counter_global_src0(u32 counter) ++{ ++ pp_counter_src0 = counter; ++} ++ ++void mali_pp_job_set_pp_counter_global_src1(u32 counter) ++{ ++ pp_counter_src1 = counter; ++} ++ ++void mali_pp_job_set_pp_counter_sub_job_src0(u32 sub_job, u32 counter) ++{ ++ MALI_DEBUG_ASSERT(sub_job < _MALI_PP_MAX_SUB_JOBS); ++ ++ if (MALI_HW_CORE_NO_COUNTER == pp_counter_per_sub_job_src0[sub_job]) { ++ /* increment count since existing counter was disabled */ ++ _mali_osk_atomic_inc(&pp_counter_per_sub_job_count); ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER == counter) { ++ /* decrement count since new counter is disabled */ ++ _mali_osk_atomic_dec(&pp_counter_per_sub_job_count); ++ } ++ ++ /* PS: A change from MALI_HW_CORE_NO_COUNTER to MALI_HW_CORE_NO_COUNTER will inc and dec, result will be 0 change */ ++ ++ pp_counter_per_sub_job_src0[sub_job] = counter; ++} ++ ++void mali_pp_job_set_pp_counter_sub_job_src1(u32 sub_job, u32 counter) ++{ ++ MALI_DEBUG_ASSERT(sub_job < _MALI_PP_MAX_SUB_JOBS); ++ ++ if (MALI_HW_CORE_NO_COUNTER == pp_counter_per_sub_job_src1[sub_job]) { ++ /* increment count since existing counter was disabled */ ++ _mali_osk_atomic_inc(&pp_counter_per_sub_job_count); ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER == counter) { ++ /* decrement count since new counter is disabled */ ++ _mali_osk_atomic_dec(&pp_counter_per_sub_job_count); ++ } ++ ++ /* PS: A change from MALI_HW_CORE_NO_COUNTER to MALI_HW_CORE_NO_COUNTER will inc and dec, result will be 0 change */ ++ ++ pp_counter_per_sub_job_src1[sub_job] = counter; ++} ++ ++u32 mali_pp_job_get_pp_counter_global_src0(void) ++{ ++ return pp_counter_src0; ++} ++ ++u32 mali_pp_job_get_pp_counter_global_src1(void) ++{ ++ return pp_counter_src1; ++} ++ ++u32 mali_pp_job_get_pp_counter_sub_job_src0(u32 sub_job) ++{ ++ MALI_DEBUG_ASSERT(sub_job < _MALI_PP_MAX_SUB_JOBS); ++ return pp_counter_per_sub_job_src0[sub_job]; ++} ++ ++u32 mali_pp_job_get_pp_counter_sub_job_src1(u32 sub_job) ++{ ++ MALI_DEBUG_ASSERT(sub_job < _MALI_PP_MAX_SUB_JOBS); ++ return pp_counter_per_sub_job_src1[sub_job]; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.h +new file mode 100644 +index 0000000..17317b4 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_job.h +@@ -0,0 +1,384 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PP_JOB_H__ ++#define __MALI_PP_JOB_H__ ++ ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_uk_types.h" ++#include "mali_session.h" ++#include "mali_kernel_common.h" ++#include "regs/mali_200_regs.h" ++#include "mali_kernel_core.h" ++#include "mali_dma.h" ++#include "mali_dlbu.h" ++#include "mali_timeline.h" ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++#include "linux/mali_memory_dma_buf.h" ++#endif ++ ++/** ++ * The structure represents a PP job, including all sub-jobs ++ * (This struct unfortunately needs to be public because of how the _mali_osk_list_* ++ * mechanism works) ++ */ ++struct mali_pp_job { ++ _mali_osk_list_t list; /**< Used to link jobs together in the scheduler queue */ ++ struct mali_session_data *session; /**< Session which submitted this job */ ++ _mali_osk_list_t session_list; /**< Used to link jobs together in the session job list */ ++ _mali_osk_list_t session_fb_lookup_list; /**< Used to link jobs together from the same frame builder in the session */ ++ _mali_uk_pp_start_job_s uargs; /**< Arguments from user space */ ++ mali_dma_cmd_buf dma_cmd_buf; /**< Command buffer for starting job using Mali-450 DMA unit */ ++ u32 id; /**< Identifier for this job in kernel space (sequential numbering) */ ++ u32 cache_order; /**< Cache order used for L2 cache flushing (sequential numbering) */ ++ u32 perf_counter_value0[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 0 (to be returned to user space), one for each sub job */ ++ u32 perf_counter_value1[_MALI_PP_MAX_SUB_JOBS]; /**< Value of performance counter 1 (to be returned to user space), one for each sub job */ ++ u32 sub_jobs_num; /**< Number of subjobs; set to 1 for Mali-450 if DLBU is used, otherwise equals number of PP cores */ ++ u32 sub_jobs_started; /**< Total number of sub-jobs started (always started in ascending order) */ ++ u32 sub_jobs_completed; /**< Number of completed sub-jobs in this superjob */ ++ u32 sub_job_errors; /**< Bitfield with errors (errors for each single sub-job is or'ed together) */ ++ u32 pid; /**< Process ID of submitting process */ ++ u32 tid; /**< Thread ID of submitting thread */ ++ _mali_osk_notification_t *finished_notification; /**< Notification sent back to userspace on job complete */ ++ u32 num_memory_cookies; /**< Number of memory cookies attached to job */ ++ u32 *memory_cookies; /**< Memory cookies attached to job */ ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++ struct mali_dma_buf_attachment **dma_bufs; /**< Array of DMA-bufs used by job */ ++ u32 num_dma_bufs; /**< Number of DMA-bufs used by job */ ++#endif ++ struct mali_timeline_tracker tracker; /**< Timeline tracker for this job */ ++ u32 perf_counter_per_sub_job_count; /**< Number of values in the two arrays which is != MALI_HW_CORE_NO_COUNTER */ ++ u32 perf_counter_per_sub_job_src0[_MALI_PP_MAX_SUB_JOBS]; /**< Per sub job counters src0 */ ++ u32 perf_counter_per_sub_job_src1[_MALI_PP_MAX_SUB_JOBS]; /**< Per sub job counters src1 */ ++}; ++ ++void mali_pp_job_initialize(void); ++void mali_pp_job_terminate(void); ++ ++struct mali_pp_job *mali_pp_job_create(struct mali_session_data *session, _mali_uk_pp_start_job_s *uargs, u32 id); ++void mali_pp_job_delete(struct mali_pp_job *job); ++ ++u32 mali_pp_job_get_perf_counter_src0(struct mali_pp_job *job, u32 sub_job); ++u32 mali_pp_job_get_perf_counter_src1(struct mali_pp_job *job, u32 sub_job); ++ ++void mali_pp_job_set_pp_counter_global_src0(u32 counter); ++void mali_pp_job_set_pp_counter_global_src1(u32 counter); ++void mali_pp_job_set_pp_counter_sub_job_src0(u32 sub_job, u32 counter); ++void mali_pp_job_set_pp_counter_sub_job_src1(u32 sub_job, u32 counter); ++ ++u32 mali_pp_job_get_pp_counter_global_src0(void); ++u32 mali_pp_job_get_pp_counter_global_src1(void); ++u32 mali_pp_job_get_pp_counter_sub_job_src0(u32 sub_job); ++u32 mali_pp_job_get_pp_counter_sub_job_src1(u32 sub_job); ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_id(struct mali_pp_job *job) ++{ ++ return (NULL == job) ? 0 : job->id; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_cache_order(struct mali_pp_job *job) ++{ ++ return (NULL == job) ? 0 : job->cache_order; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_user_id(struct mali_pp_job *job) ++{ ++ return job->uargs.user_job_ptr; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_frame_builder_id(struct mali_pp_job *job) ++{ ++ return job->uargs.frame_builder_id; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_flush_id(struct mali_pp_job *job) ++{ ++ return job->uargs.flush_id; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_pid(struct mali_pp_job *job) ++{ ++ return job->pid; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_tid(struct mali_pp_job *job) ++{ ++ return job->tid; ++} ++ ++MALI_STATIC_INLINE u32* mali_pp_job_get_frame_registers(struct mali_pp_job *job) ++{ ++ return job->uargs.frame_registers; ++} ++ ++MALI_STATIC_INLINE u32* mali_pp_job_get_dlbu_registers(struct mali_pp_job *job) ++{ ++ return job->uargs.dlbu_registers; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_is_virtual(struct mali_pp_job *job) ++{ ++#if defined(CONFIG_MALI450) ++ return 0 == job->uargs.num_cores; ++#else ++ return MALI_FALSE; ++#endif ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_addr_frame(struct mali_pp_job *job, u32 sub_job) ++{ ++ if (mali_pp_job_is_virtual(job)) { ++ return MALI_DLBU_VIRT_ADDR; ++ } else if (0 == sub_job) { ++ return job->uargs.frame_registers[MALI200_REG_ADDR_FRAME / sizeof(u32)]; ++ } else if (sub_job < _MALI_PP_MAX_SUB_JOBS) { ++ return job->uargs.frame_registers_addr_frame[sub_job - 1]; ++ } ++ ++ return 0; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_addr_stack(struct mali_pp_job *job, u32 sub_job) ++{ ++ if (0 == sub_job) { ++ return job->uargs.frame_registers[MALI200_REG_ADDR_STACK / sizeof(u32)]; ++ } else if (sub_job < _MALI_PP_MAX_SUB_JOBS) { ++ return job->uargs.frame_registers_addr_stack[sub_job - 1]; ++ } ++ ++ return 0; ++} ++ ++MALI_STATIC_INLINE u32* mali_pp_job_get_wb0_registers(struct mali_pp_job *job) ++{ ++ return job->uargs.wb0_registers; ++} ++ ++MALI_STATIC_INLINE u32* mali_pp_job_get_wb1_registers(struct mali_pp_job *job) ++{ ++ return job->uargs.wb1_registers; ++} ++ ++MALI_STATIC_INLINE u32* mali_pp_job_get_wb2_registers(struct mali_pp_job *job) ++{ ++ return job->uargs.wb2_registers; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_disable_wb0(struct mali_pp_job *job) ++{ ++ job->uargs.wb0_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_disable_wb1(struct mali_pp_job *job) ++{ ++ job->uargs.wb1_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_disable_wb2(struct mali_pp_job *job) ++{ ++ job->uargs.wb2_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] = 0; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_all_writeback_unit_disabled(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ if ( job->uargs.wb0_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] || ++ job->uargs.wb1_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] || ++ job->uargs.wb2_registers[MALI200_REG_ADDR_WB_SOURCE_SELECT] ++ ) { ++ /* At least one output unit active */ ++ return MALI_FALSE; ++ } ++ ++ /* All outputs are disabled - we can abort the job */ ++ return MALI_TRUE; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_fb_lookup_id(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ return MALI_PP_JOB_FB_LOOKUP_LIST_MASK & job->uargs.frame_builder_id; ++} ++ ++MALI_STATIC_INLINE struct mali_session_data *mali_pp_job_get_session(struct mali_pp_job *job) ++{ ++ return job->session; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_has_unstarted_sub_jobs(struct mali_pp_job *job) ++{ ++ return (job->sub_jobs_started < job->sub_jobs_num) ? MALI_TRUE : MALI_FALSE; ++} ++ ++/* Function used when we are terminating a session with jobs. Return TRUE if it has a rendering job. ++ Makes sure that no new subjobs are started. */ ++MALI_STATIC_INLINE void mali_pp_job_mark_unstarted_failed(struct mali_pp_job *job) ++{ ++ u32 jobs_remaining = job->sub_jobs_num - job->sub_jobs_started; ++ job->sub_jobs_started += jobs_remaining; ++ job->sub_jobs_completed += jobs_remaining; ++ job->sub_job_errors += jobs_remaining; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_mark_unstarted_success(struct mali_pp_job *job) ++{ ++ u32 jobs_remaining = job->sub_jobs_num - job->sub_jobs_started; ++ job->sub_jobs_started += jobs_remaining; ++ job->sub_jobs_completed += jobs_remaining; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_is_complete(struct mali_pp_job *job) ++{ ++ return (job->sub_jobs_num == job->sub_jobs_completed) ? MALI_TRUE : MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_first_unstarted_sub_job(struct mali_pp_job *job) ++{ ++ return job->sub_jobs_started; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_sub_job_count(struct mali_pp_job *job) ++{ ++ return job->sub_jobs_num; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_needs_dma_buf_mapping(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT(job); ++ ++ if (0 != job->num_memory_cookies) { ++ return MALI_TRUE; ++ } ++ ++ return MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_started(struct mali_pp_job *job, u32 sub_job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ /* Assert that we are marking the "first unstarted sub job" as started */ ++ MALI_DEBUG_ASSERT(job->sub_jobs_started == sub_job); ++ ++ job->sub_jobs_started++; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_mark_sub_job_completed(struct mali_pp_job *job, mali_bool success) ++{ ++ job->sub_jobs_completed++; ++ if ( MALI_FALSE == success ) { ++ job->sub_job_errors++; ++ } ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_was_success(struct mali_pp_job *job) ++{ ++ if ( 0 == job->sub_job_errors ) { ++ return MALI_TRUE; ++ } ++ return MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_pp_job_use_no_notification(struct mali_pp_job *job) ++{ ++ return job->uargs.flags & _MALI_PP_JOB_FLAG_NO_NOTIFICATION ? MALI_TRUE : MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_flag(struct mali_pp_job *job) ++{ ++ return job->uargs.perf_counter_flag; ++} ++ ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value0(struct mali_pp_job *job, u32 sub_job) ++{ ++ return job->perf_counter_value0[sub_job]; ++} ++ ++MALI_STATIC_INLINE u32 mali_pp_job_get_perf_counter_value1(struct mali_pp_job *job, u32 sub_job) ++{ ++ return job->perf_counter_value1[sub_job]; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value0(struct mali_pp_job *job, u32 sub_job, u32 value) ++{ ++ job->perf_counter_value0[sub_job] = value; ++} ++ ++MALI_STATIC_INLINE void mali_pp_job_set_perf_counter_value1(struct mali_pp_job *job, u32 sub_job, u32 value) ++{ ++ job->perf_counter_value1[sub_job] = value; ++} ++ ++MALI_STATIC_INLINE _mali_osk_errcode_t mali_pp_job_check(struct mali_pp_job *job) ++{ ++ if (mali_pp_job_is_virtual(job) && job->sub_jobs_num != 1) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ return _MALI_OSK_ERR_OK; ++} ++ ++/** ++ * Returns MALI_TRUE if first job should be started after second job. ++ * ++ * @param first First job. ++ * @param second Second job. ++ * @return MALI_TRUE if first job should be started after second job, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_pp_job_should_start_after(struct mali_pp_job *first, struct mali_pp_job *second) ++{ ++ MALI_DEBUG_ASSERT_POINTER(first); ++ MALI_DEBUG_ASSERT_POINTER(second); ++ ++ /* First job should be started after second job if second job is in progress. */ ++ if (0 < second->sub_jobs_started) { ++ return MALI_TRUE; ++ } ++ ++ /* First job should be started after second job if first job has a higher job id. A span is ++ used to handle job id wrapping. */ ++ if ((mali_pp_job_get_id(first) - mali_pp_job_get_id(second)) < MALI_SCHEDULER_JOB_ID_SPAN) { ++ return MALI_TRUE; ++ } ++ ++ /* Second job should be started after first job. */ ++ return MALI_FALSE; ++} ++ ++/** ++ * Returns MALI_TRUE if this job has more than two sub jobs and all sub jobs are unstarted. ++ * ++ * @param job Job to check. ++ * @return MALI_TRUE if job has more than two sub jobs and all sub jobs are unstarted, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_pp_job_is_large_and_unstarted(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job)); ++ ++ return (0 == job->sub_jobs_started && 2 < job->sub_jobs_num); ++} ++ ++/** ++ * Get PP job's Timeline tracker. ++ * ++ * @param job PP job. ++ * @return Pointer to Timeline tracker for the job. ++ */ ++MALI_STATIC_INLINE struct mali_timeline_tracker *mali_pp_job_get_tracker(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ return &(job->tracker); ++} ++ ++#endif /* __MALI_PP_JOB_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.c +new file mode 100644 +index 0000000..8dd8e3e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.c +@@ -0,0 +1,2067 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_pp_scheduler.h" ++#include "mali_kernel_common.h" ++#include "mali_kernel_core.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_scheduler.h" ++#include "mali_pp.h" ++#include "mali_pp_job.h" ++#include "mali_group.h" ++#include "mali_pm.h" ++#include "mali_timeline.h" ++#include "mali_osk_profiling.h" ++#include "mali_kernel_utilization.h" ++#include "mali_session.h" ++#include "mali_pm_domain.h" ++#include "linux/mali/mali_utgard.h" ++ ++#if defined(CONFIG_DMA_SHARED_BUFFER) ++#include "mali_memory_dma_buf.h" ++#endif ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++#include ++#include ++#endif ++ ++/* Queue type used for physical and virtual job queues. */ ++struct mali_pp_scheduler_job_queue { ++ _MALI_OSK_LIST_HEAD(normal_pri); /* List of jobs with some unscheduled work. */ ++ _MALI_OSK_LIST_HEAD(high_pri); /* List of high priority jobs with some unscheduled work. */ ++ u32 depth; /* Depth of combined queues. */ ++}; ++ ++/* If dma_buf with map on demand is used, we defer job deletion and job queue if in atomic context, ++ * since both might sleep. */ ++#if defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++#define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE 1 ++#define MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE 1 ++#endif /* !defined(CONFIG_DMA_SHARED_BUFFER) && !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) */ ++ ++static void mali_pp_scheduler_job_queued(void); ++static void mali_pp_scheduler_job_completed(void); ++ ++/* Maximum of 8 PP cores (a group can only have maximum of 1 PP core) */ ++#define MALI_MAX_NUMBER_OF_PP_GROUPS 9 ++ ++static mali_bool mali_pp_scheduler_is_suspended(void *data); ++ ++static u32 pp_version = 0; ++ ++/* Physical job queue */ ++static struct mali_pp_scheduler_job_queue job_queue; ++ ++/* Physical groups */ ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_working); /* List of physical groups with working jobs on the pp core */ ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_idle); /* List of physical groups with idle jobs on the pp core */ ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(group_list_disabled); /* List of disabled physical groups */ ++ ++/* Virtual job queue (Mali-450 only) */ ++static struct mali_pp_scheduler_job_queue virtual_job_queue; ++ ++/** ++ * Add job to scheduler queue. ++ * ++ * @param job Job to queue. ++ * @return Schedule mask. ++ */ ++static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job); ++ ++/* Virtual group (Mali-450 only) */ ++static struct mali_group *virtual_group = NULL; /* Virtual group (if any) */ ++static enum { ++ VIRTUAL_GROUP_IDLE, ++ VIRTUAL_GROUP_WORKING, ++ VIRTUAL_GROUP_DISABLED, ++} ++virtual_group_state = VIRTUAL_GROUP_IDLE; /* Flag which indicates whether the virtual group is working or idle */ ++ ++/* Number of physical cores */ ++static u32 num_cores = 0; ++ ++/* Number of physical cores which are enabled */ ++static u32 enabled_cores = 0; ++ ++/* Enable or disable core scaling */ ++static mali_bool core_scaling_enabled = MALI_TRUE; ++ ++/* Variables to allow safe pausing of the scheduler */ ++static _mali_osk_wait_queue_t *pp_scheduler_working_wait_queue = NULL; ++static u32 pause_count = 0; ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++static _mali_osk_spinlock_irq_t *pp_scheduler_lock = NULL; ++#else ++static _mali_osk_spinlock_t *pp_scheduler_lock = NULL; ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_lock(void) ++{ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_lock(pp_scheduler_lock); ++#else ++ _mali_osk_spinlock_lock(pp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ MALI_DEBUG_PRINT(5, ("Mali PP scheduler: PP scheduler lock taken.\n")); ++} ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_unlock(void) ++{ ++ MALI_DEBUG_PRINT(5, ("Mali PP scheduler: Releasing PP scheduler lock.\n")); ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_unlock(pp_scheduler_lock); ++#else ++ _mali_osk_spinlock_unlock(pp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++} ++ ++#if defined(DEBUG) ++#define MALI_ASSERT_PP_SCHEDULER_LOCKED() MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock) ++#else ++#define MALI_ASSERT_PP_SCHEDULER_LOCKED() do {} while (0) ++#endif /* defined(DEBUG) */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ ++static _mali_osk_wq_work_t *pp_scheduler_wq_job_delete = NULL; ++static _mali_osk_spinlock_irq_t *pp_scheduler_job_delete_lock = NULL; ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_deletion_queue); ++ ++static void mali_pp_scheduler_deferred_job_delete(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock); ++ ++ /* This job object should not be on any lists. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list)); ++ ++ _mali_osk_list_addtail(&job->list, &pp_scheduler_job_deletion_queue); ++ ++ _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock); ++ ++ _mali_osk_wq_schedule_work(pp_scheduler_wq_job_delete); ++} ++ ++static void mali_pp_scheduler_do_job_delete(void *arg) ++{ ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(list); ++ struct mali_pp_job *job; ++ struct mali_pp_job *tmp; ++ ++ MALI_IGNORE(arg); ++ ++ _mali_osk_spinlock_irq_lock(pp_scheduler_job_delete_lock); ++ ++ /* ++ * Quickly "unhook" the jobs pending to be deleted, so we can release the lock before ++ * we start deleting the job objects (without any locks held ++ */ ++ _mali_osk_list_move_list(&pp_scheduler_job_deletion_queue, &list); ++ ++ _mali_osk_spinlock_irq_unlock(pp_scheduler_job_delete_lock); ++ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) { ++ mali_pp_job_delete(job); /* delete the job object itself */ ++ } ++} ++ ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ ++static _mali_osk_wq_work_t *pp_scheduler_wq_job_queue = NULL; ++static _mali_osk_spinlock_irq_t *pp_scheduler_job_queue_lock = NULL; ++static _MALI_OSK_LIST_HEAD_STATIC_INIT(pp_scheduler_job_queue_list); ++ ++static void mali_pp_scheduler_deferred_job_queue(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock); ++ _mali_osk_list_addtail(&job->list, &pp_scheduler_job_queue_list); ++ _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock); ++ ++ _mali_osk_wq_schedule_work(pp_scheduler_wq_job_queue); ++} ++ ++static void mali_pp_scheduler_do_job_queue(void *arg) ++{ ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(list); ++ struct mali_pp_job *job; ++ struct mali_pp_job *tmp; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_IGNORE(arg); ++ ++ _mali_osk_spinlock_irq_lock(pp_scheduler_job_queue_lock); ++ ++ /* ++ * Quickly "unhook" the jobs pending to be queued, so we can release the lock before ++ * we start queueing the job objects (without any locks held) ++ */ ++ _mali_osk_list_move_list(&pp_scheduler_job_queue_list, &list); ++ ++ _mali_osk_spinlock_irq_unlock(pp_scheduler_job_queue_lock); ++ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &list, struct mali_pp_job, list) { ++ _mali_osk_list_delinit(&job->list); ++ schedule_mask |= mali_pp_scheduler_queue_job(job); ++ } ++ ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE); ++} ++ ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++MALI_STATIC_INLINE mali_bool mali_pp_scheduler_has_virtual_group(void) ++{ ++#if defined(CONFIG_MALI450) ++ return NULL != virtual_group; ++#else ++ return MALI_FALSE; ++#endif /* defined(CONFIG_MALI450) */ ++} ++ ++_mali_osk_errcode_t mali_pp_scheduler_initialize(void) ++{ ++ _MALI_OSK_INIT_LIST_HEAD(&job_queue.normal_pri); ++ _MALI_OSK_INIT_LIST_HEAD(&job_queue.high_pri); ++ job_queue.depth = 0; ++ ++ _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.normal_pri); ++ _MALI_OSK_INIT_LIST_HEAD(&virtual_job_queue.high_pri); ++ virtual_job_queue.depth = 0; ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ pp_scheduler_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER); ++#else ++ pp_scheduler_lock = _mali_osk_spinlock_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ if (NULL == pp_scheduler_lock) goto cleanup; ++ ++ pp_scheduler_working_wait_queue = _mali_osk_wait_queue_init(); ++ if (NULL == pp_scheduler_working_wait_queue) goto cleanup; ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ pp_scheduler_wq_job_delete = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_delete, NULL); ++ if (NULL == pp_scheduler_wq_job_delete) goto cleanup; ++ ++ pp_scheduler_job_delete_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED); ++ if (NULL == pp_scheduler_job_delete_lock) goto cleanup; ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ pp_scheduler_wq_job_queue = _mali_osk_wq_create_work(mali_pp_scheduler_do_job_queue, NULL); ++ if (NULL == pp_scheduler_wq_job_queue) goto cleanup; ++ ++ pp_scheduler_job_queue_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER_DEFERRED); ++ if (NULL == pp_scheduler_job_queue_lock) goto cleanup; ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++ return _MALI_OSK_ERR_OK; ++ ++cleanup: ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ if (NULL != pp_scheduler_job_queue_lock) { ++ _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock); ++ pp_scheduler_job_queue_lock = NULL; ++ } ++ ++ if (NULL != pp_scheduler_wq_job_queue) { ++ _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue); ++ pp_scheduler_wq_job_queue = NULL; ++ } ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ if (NULL != pp_scheduler_job_delete_lock) { ++ _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock); ++ pp_scheduler_job_delete_lock = NULL; ++ } ++ ++ if (NULL != pp_scheduler_wq_job_delete) { ++ _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete); ++ pp_scheduler_wq_job_delete = NULL; ++ } ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */ ++ ++ if (NULL != pp_scheduler_working_wait_queue) { ++ _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue); ++ pp_scheduler_working_wait_queue = NULL; ++ } ++ ++ if (NULL != pp_scheduler_lock) { ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_term(pp_scheduler_lock); ++#else ++ _mali_osk_spinlock_term(pp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++ pp_scheduler_lock = NULL; ++ } ++ ++ return _MALI_OSK_ERR_NOMEM; ++} ++ ++void mali_pp_scheduler_terminate(void) ++{ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ _mali_osk_spinlock_irq_term(pp_scheduler_job_queue_lock); ++ _mali_osk_wq_delete_work(pp_scheduler_wq_job_queue); ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ _mali_osk_spinlock_irq_term(pp_scheduler_job_delete_lock); ++ _mali_osk_wq_delete_work(pp_scheduler_wq_job_delete); ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */ ++ ++ _mali_osk_wait_queue_term(pp_scheduler_working_wait_queue); ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ _mali_osk_spinlock_irq_term(pp_scheduler_lock); ++#else ++ _mali_osk_spinlock_term(pp_scheduler_lock); ++#endif /* defined(MALI_UPPER_HALF_SCHEDULING) */ ++} ++ ++void mali_pp_scheduler_populate(void) ++{ ++ struct mali_group *group; ++ struct mali_pp_core *pp_core; ++ u32 num_groups; ++ u32 i; ++ ++ num_groups = mali_group_get_glob_num_groups(); ++ ++ /* Do we have a virtual group? */ ++ for (i = 0; i < num_groups; i++) { ++ group = mali_group_get_glob_group(i); ++ ++ if (mali_group_is_virtual(group)) { ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Found virtual group %p.\n", group)); ++ ++ virtual_group = group; ++ break; ++ } ++ } ++ ++ /* Find all the available PP cores */ ++ for (i = 0; i < num_groups; i++) { ++ group = mali_group_get_glob_group(i); ++ pp_core = mali_group_get_pp_core(group); ++ ++ if (NULL != pp_core && !mali_group_is_virtual(group)) { ++ if (0 == pp_version) { ++ /* Retrieve PP version from the first available PP core */ ++ pp_version = mali_pp_core_get_version(pp_core); ++ } ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ /* Add all physical PP cores to the virtual group */ ++ mali_group_lock(virtual_group); ++ group->state = MALI_GROUP_STATE_JOINING_VIRTUAL; ++ mali_group_add_group(virtual_group, group, MALI_TRUE); ++ mali_group_unlock(virtual_group); ++ } else { ++ _mali_osk_list_add(&group->pp_scheduler_list, &group_list_idle); ++ } ++ ++ num_cores++; ++ } ++ } ++ ++ enabled_cores = num_cores; ++} ++ ++void mali_pp_scheduler_depopulate(void) ++{ ++ struct mali_group *group, *temp; ++ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working)); ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state); ++ ++ /* Delete all groups owned by scheduler */ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_delete(virtual_group); ++ } ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) { ++ mali_group_delete(group); ++ } ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) { ++ mali_group_delete(group); ++ } ++} ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_disable_empty_virtual(void) ++{ ++ MALI_ASSERT_GROUP_LOCKED(virtual_group); ++ ++ if (mali_group_virtual_disable_if_empty(virtual_group)) { ++ MALI_DEBUG_PRINT(4, ("Disabling empty virtual group\n")); ++ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state); ++ ++ virtual_group_state = VIRTUAL_GROUP_DISABLED; ++ } ++} ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_enable_empty_virtual(void) ++{ ++ MALI_ASSERT_GROUP_LOCKED(virtual_group); ++ ++ if (mali_group_virtual_enable_if_empty(virtual_group)) { ++ MALI_DEBUG_PRINT(4, ("Re-enabling empty virtual group\n")); ++ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_DISABLED == virtual_group_state); ++ ++ virtual_group_state = VIRTUAL_GROUP_IDLE; ++ } ++} ++ ++static struct mali_pp_job *mali_pp_scheduler_get_job(struct mali_pp_scheduler_job_queue *queue) ++{ ++ struct mali_pp_job *job = NULL; ++ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ MALI_DEBUG_ASSERT_POINTER(queue); ++ ++ /* Check if we have a normal priority job. */ ++ if (!_mali_osk_list_empty(&queue->normal_pri)) { ++ MALI_DEBUG_ASSERT(queue->depth > 0); ++ job = _MALI_OSK_LIST_ENTRY(queue->normal_pri.next, struct mali_pp_job, list); ++ } ++ ++ /* Prefer normal priority job if it is in progress. */ ++ if (NULL != job && 0 < job->sub_jobs_started) { ++ return job; ++ } ++ ++ /* Check if we have a high priority job. */ ++ if (!_mali_osk_list_empty(&queue->high_pri)) { ++ MALI_DEBUG_ASSERT(queue->depth > 0); ++ job = _MALI_OSK_LIST_ENTRY(queue->high_pri.next, struct mali_pp_job, list); ++ } ++ ++ return job; ++} ++ ++/** ++ * Returns a physical job if a physical job is ready to run ++ */ ++MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_physical_job(void) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ return mali_pp_scheduler_get_job(&job_queue); ++} ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_physical_job(struct mali_pp_job *job) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ MALI_DEBUG_ASSERT(job_queue.depth > 0); ++ ++ /* Remove job from queue */ ++ if (!mali_pp_job_has_unstarted_sub_jobs(job)) { ++ /* All sub jobs have been started: remove job from queue */ ++ _mali_osk_list_delinit(&job->list); ++ _mali_osk_list_delinit(&job->session_fb_lookup_list); ++ } ++ ++ --job_queue.depth; ++} ++ ++/** ++ * Returns a virtual job if a virtual job is ready to run ++ */ ++MALI_STATIC_INLINE struct mali_pp_job *mali_pp_scheduler_get_virtual_job(void) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ MALI_DEBUG_ASSERT_POINTER(virtual_group); ++ return mali_pp_scheduler_get_job(&virtual_job_queue); ++} ++ ++MALI_STATIC_INLINE void mali_pp_scheduler_dequeue_virtual_job(struct mali_pp_job *job) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ MALI_DEBUG_ASSERT(virtual_job_queue.depth > 0); ++ ++ /* Remove job from queue */ ++ _mali_osk_list_delinit(&job->list); ++ _mali_osk_list_delinit(&job->session_fb_lookup_list); ++ --virtual_job_queue.depth; ++} ++ ++/** ++ * Checks if the criteria is met for removing a physical core from virtual group ++ */ ++MALI_STATIC_INLINE mali_bool mali_pp_scheduler_can_move_virtual_to_physical(void) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ MALI_DEBUG_ASSERT(mali_pp_scheduler_has_virtual_group()); ++ MALI_ASSERT_GROUP_LOCKED(virtual_group); ++ /* ++ * The criteria for taking out a physical group from a virtual group are the following: ++ * - There virtual group is idle ++ * - There are currently no physical groups (idle and working) ++ * - There are physical jobs to be scheduled ++ */ ++ return (VIRTUAL_GROUP_IDLE == virtual_group_state) && ++ _mali_osk_list_empty(&group_list_idle) && ++ _mali_osk_list_empty(&group_list_working) && ++ (NULL != mali_pp_scheduler_get_physical_job()); ++} ++ ++MALI_STATIC_INLINE struct mali_group *mali_pp_scheduler_acquire_physical_group(void) ++{ ++ MALI_ASSERT_PP_SCHEDULER_LOCKED(); ++ ++ if (!_mali_osk_list_empty(&group_list_idle)) { ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from idle list.\n")); ++ return _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list); ++ } else if (mali_pp_scheduler_has_virtual_group()) { ++ MALI_ASSERT_GROUP_LOCKED(virtual_group); ++ if (mali_pp_scheduler_can_move_virtual_to_physical()) { ++ struct mali_group *group; ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquiring physical group from virtual group.\n")); ++ group = mali_group_acquire_group(virtual_group); ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_pp_scheduler_disable_empty_virtual(); ++ } ++ ++ return group; ++ } ++ } ++ ++ return NULL; ++} ++ ++static void mali_pp_scheduler_return_job_to_user(struct mali_pp_job *job, mali_bool deferred) ++{ ++ if (MALI_FALSE == mali_pp_job_use_no_notification(job)) { ++ u32 i; ++ u32 num_counters_to_copy; ++ mali_bool success = mali_pp_job_was_success(job); ++ ++ _mali_uk_pp_job_finished_s *jobres = job->finished_notification->result_buffer; ++ _mali_osk_memset(jobres, 0, sizeof(_mali_uk_pp_job_finished_s)); /* @@@@ can be removed once we initialize all members in this struct */ ++ jobres->user_job_ptr = mali_pp_job_get_user_id(job); ++ if (MALI_TRUE == success) { ++ jobres->status = _MALI_UK_JOB_STATUS_END_SUCCESS; ++ } else { ++ jobres->status = _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR; ++ } ++ ++ if (mali_pp_job_is_virtual(job)) { ++ num_counters_to_copy = num_cores; /* Number of physical cores available */ ++ } else { ++ num_counters_to_copy = mali_pp_job_get_sub_job_count(job); ++ } ++ ++ for (i = 0; i < num_counters_to_copy; i++) { ++ jobres->perf_counter0[i] = mali_pp_job_get_perf_counter_value0(job, i); ++ jobres->perf_counter1[i] = mali_pp_job_get_perf_counter_value1(job, i); ++ jobres->perf_counter_src0 = mali_pp_job_get_pp_counter_global_src0(); ++ jobres->perf_counter_src1 = mali_pp_job_get_pp_counter_global_src1(); ++ } ++ ++ mali_session_send_notification(mali_pp_job_get_session(job), job->finished_notification); ++ job->finished_notification = NULL; ++ } ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ if (MALI_TRUE == deferred) { ++ /* The deletion of the job object (releasing sync refs etc) must be done in a different context */ ++ mali_pp_scheduler_deferred_job_delete(job); ++ } else { ++ mali_pp_job_delete(job); ++ } ++#else ++ MALI_DEBUG_ASSERT(MALI_FALSE == deferred); /* no use cases need this in this configuration */ ++ mali_pp_job_delete(job); ++#endif ++} ++ ++static void mali_pp_scheduler_finalize_job(struct mali_pp_job * job) ++{ ++ /* This job object should not be on any lists. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list)); ++ ++ /* Send notification back to user space */ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ mali_pp_scheduler_return_job_to_user(job, MALI_TRUE); ++#else ++ mali_pp_scheduler_return_job_to_user(job, MALI_FALSE); ++#endif ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ if (_MALI_PP_JOB_FLAG_IS_WINDOW_SURFACE & job->uargs.flags) { ++ _mali_osk_atomic_inc(&job->session->number_of_window_jobs); ++ } ++#endif ++ ++ mali_pp_scheduler_job_completed(); ++} ++ ++void mali_pp_scheduler_schedule(void) ++{ ++ struct mali_group* physical_groups_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1]; ++ struct mali_pp_job* physical_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1]; ++ u32 physical_sub_jobs_to_start[MALI_MAX_NUMBER_OF_PP_GROUPS - 1]; ++ int num_physical_jobs_to_start = 0; ++ int i; ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ /* Lock the virtual group since we might have to grab physical groups. */ ++ mali_group_lock(virtual_group); ++ } ++ ++ mali_pp_scheduler_lock(); ++ if (pause_count > 0) { ++ /* Scheduler is suspended, don't schedule any jobs. */ ++ mali_pp_scheduler_unlock(); ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_unlock(virtual_group); ++ } ++ return; ++ } ++ ++ /* Find physical job(s) to schedule first. */ ++ while (1) { ++ struct mali_group *group; ++ struct mali_pp_job *job; ++ u32 sub_job; ++ ++ job = mali_pp_scheduler_get_physical_job(); ++ if (NULL == job) { ++ break; /* No job, early out. */ ++ } ++ ++ if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) && ++ mali_pp_job_is_large_and_unstarted(job) && !_mali_osk_list_empty(&group_list_working)) { ++ /* Since not all groups are idle, don't schedule yet. */ ++ break; ++ } ++ ++ MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job)); ++ MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); ++ MALI_DEBUG_ASSERT(1 <= mali_pp_job_get_sub_job_count(job)); ++ ++ /* Acquire a physical group, either from the idle list or from the virtual group. ++ * In case the group was acquired from the virtual group, it's state will be ++ * LEAVING_VIRTUAL and must be set to IDLE before it can be used. */ ++ group = mali_pp_scheduler_acquire_physical_group(); ++ if (NULL == group) { ++ /* Could not get a group to run the job on, early out. */ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: No more physical groups available.\n")); ++ break; ++ } ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Acquired physical group %p.\n", group)); ++ ++ /* Mark sub job as started. */ ++ sub_job = mali_pp_job_get_first_unstarted_sub_job(job); ++ mali_pp_job_mark_sub_job_started(job, sub_job); ++ ++ /* Remove job from queue (if this was the last sub job). */ ++ mali_pp_scheduler_dequeue_physical_job(job); ++ ++ /* Move group to working list. */ ++ _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_working); ++ ++ /* Keep track of this group, so that we actually can start the job once we are done with the scheduler lock we are now holding. */ ++ physical_groups_to_start[num_physical_jobs_to_start] = group; ++ physical_jobs_to_start[num_physical_jobs_to_start] = job; ++ physical_sub_jobs_to_start[num_physical_jobs_to_start] = sub_job; ++ ++num_physical_jobs_to_start; ++ ++ MALI_DEBUG_ASSERT(num_physical_jobs_to_start < MALI_MAX_NUMBER_OF_PP_GROUPS); ++ } ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ if (VIRTUAL_GROUP_IDLE == virtual_group_state) { ++ /* We have a virtual group and it is idle. */ ++ ++ struct mali_pp_job *job; ++ ++ /* Find a virtual job we can start. */ ++ job = mali_pp_scheduler_get_virtual_job(); ++ ++ if (NULL != job) { ++ MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job)); ++ MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); ++ MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job)); ++ ++ /* Mark the one and only sub job as started. */ ++ mali_pp_job_mark_sub_job_started(job, 0); ++ ++ /* Remove job from queue. */ ++ mali_pp_scheduler_dequeue_virtual_job(job); ++ ++ /* Virtual group is now working. */ ++ virtual_group_state = VIRTUAL_GROUP_WORKING; ++ ++ /* We no longer need the scheduler lock, but we still need the virtual lock ++ * in order to start the virtual job. */ ++ mali_pp_scheduler_unlock(); ++ ++ /* Start job. */ ++ mali_group_start_pp_job(virtual_group, job, 0); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from schedule).\n", ++ mali_pp_job_get_id(job), job, 1, ++ mali_pp_job_get_sub_job_count(job))); ++ ++ mali_group_unlock(virtual_group); ++ } else { ++ /* No virtual job to start. */ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(virtual_group); ++ } ++ } else { ++ /* We have a virtual group, but it is busy or disabled. */ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE != virtual_group_state); ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(virtual_group); ++ } ++ } else { ++ /* There is no virtual group. */ ++ mali_pp_scheduler_unlock(); ++ } ++ ++ /* We have now released the scheduler lock, and we are ready to start the physical jobs. ++ * The reason we want to wait until we have released the scheduler lock is that job start ++ * may take quite a bit of time (many registers have to be written). This will allow new ++ * jobs from user space to come in, and post-processing of other PP jobs to happen at the ++ * same time as we start jobs. */ ++ for (i = 0; i < num_physical_jobs_to_start; i++) { ++ struct mali_group *group = physical_groups_to_start[i]; ++ struct mali_pp_job *job = physical_jobs_to_start[i]; ++ u32 sub_job = physical_sub_jobs_to_start[i]; ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT(!mali_group_is_virtual(group)); ++ MALI_DEBUG_ASSERT(!mali_pp_job_is_virtual(job)); ++ ++ mali_group_lock(group); ++ ++ /* Set state to IDLE if group was acquired from the virtual group. */ ++ group->state = MALI_GROUP_STATE_IDLE; ++ ++ mali_group_start_pp_job(group, job, sub_job); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from schedule).\n", ++ mali_pp_job_get_id(job), job, sub_job + 1, ++ mali_pp_job_get_sub_job_count(job))); ++ ++ mali_group_unlock(group); ++ } ++} ++ ++/** ++ * Set group idle. ++ * ++ * If @ref group is the virtual group, nothing is done since the virtual group should be idle ++ * already. ++ * ++ * If @ref group is a physical group we rejoin the virtual group, if it exists. If not, we move the ++ * physical group to the idle list. ++ * ++ * @note The group and the scheduler must both be locked when entering this function. Both will be ++ * unlocked before exiting. ++ * ++ * @param group The group to set idle. ++ */ ++static void mali_pp_scheduler_set_group_idle_and_unlock(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock); ++ ++ if (mali_group_is_virtual(group)) { ++ /* The virtual group should have been set to non-working already. */ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state); ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ ++ return; ++ } else { ++ if (mali_pp_scheduler_has_virtual_group()) { ++ /* Rejoin virtual group. */ ++ ++ /* We're no longer needed on the scheduler list. */ ++ _mali_osk_list_delinit(&(group->pp_scheduler_list)); ++ ++ /* Make sure no interrupts are handled for this group during the transition ++ * from physical to virtual. */ ++ group->state = MALI_GROUP_STATE_JOINING_VIRTUAL; ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ ++ mali_group_lock(virtual_group); ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_pp_scheduler_enable_empty_virtual(); ++ } ++ ++ /* We need to recheck the group state since it is possible that someone has ++ * modified the group before we locked the virtual group. */ ++ if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) { ++ mali_group_add_group(virtual_group, group, MALI_TRUE); ++ } ++ ++ mali_group_unlock(virtual_group); ++ } else { ++ /* Move physical group back to idle list. */ ++ _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle); ++ ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0); ++#endif ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ } ++ } ++} ++ ++/** ++ * Schedule job on locked group. ++ * ++ * @note The group and the scheduler must both be locked when entering this function. Both will be ++ * unlocked before exiting. ++ * ++ * @param group The group to schedule on. ++ */ ++static void mali_pp_scheduler_schedule_on_group_and_unlock(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock); ++ ++ if (mali_group_is_virtual(group)) { ++ /* Now that the virtual group is idle, check if we should reconfigure. */ ++ ++ struct mali_pp_job *virtual_job = NULL; ++ struct mali_pp_job *physical_job = NULL; ++ struct mali_group *physical_group = NULL; ++ u32 physical_sub_job = 0; ++ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_IDLE == virtual_group_state); ++ ++ if (mali_pp_scheduler_can_move_virtual_to_physical()) { ++ /* There is a runnable physical job and we can acquire a physical group. */ ++ physical_job = mali_pp_scheduler_get_physical_job(); ++ MALI_DEBUG_ASSERT_POINTER(physical_job); ++ MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(physical_job)); ++ ++ /* Mark sub job as started. */ ++ physical_sub_job = mali_pp_job_get_first_unstarted_sub_job(physical_job); ++ mali_pp_job_mark_sub_job_started(physical_job, physical_sub_job); ++ ++ /* Remove job from queue (if this was the last sub job). */ ++ mali_pp_scheduler_dequeue_physical_job(physical_job); ++ ++ /* Acquire a physical group from the virtual group. Its state will ++ * be LEAVING_VIRTUAL and must be set to IDLE before it can be ++ * used. */ ++ physical_group = mali_group_acquire_group(virtual_group); ++ ++ /* Move physical group to the working list, as we will soon start a job on it. */ ++ _mali_osk_list_move(&(physical_group->pp_scheduler_list), &group_list_working); ++ ++ mali_pp_scheduler_disable_empty_virtual(); ++ } ++ ++ /* Get next virtual job. */ ++ virtual_job = mali_pp_scheduler_get_virtual_job(); ++ if (NULL != virtual_job && VIRTUAL_GROUP_IDLE == virtual_group_state) { ++ /* There is a runnable virtual job. */ ++ ++ MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(virtual_job)); ++ MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(virtual_job)); ++ MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(virtual_job)); ++ ++ mali_pp_job_mark_sub_job_started(virtual_job, 0); ++ ++ /* Remove job from queue. */ ++ mali_pp_scheduler_dequeue_virtual_job(virtual_job); ++ ++ /* Virtual group is now working. */ ++ virtual_group_state = VIRTUAL_GROUP_WORKING; ++ ++ mali_pp_scheduler_unlock(); ++ ++ /* Start job. */ ++ mali_group_start_pp_job(group, virtual_job, 0); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Virtual job %u (0x%08X) part %u/%u started (from job_done).\n", ++ mali_pp_job_get_id(virtual_job), virtual_job, 1, ++ mali_pp_job_get_sub_job_count(virtual_job))); ++ } else { ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch("Mali_Virtual_PP", sched_clock(), 0, 0, 0); ++#endif ++ ++ mali_pp_scheduler_unlock(); ++ } ++ ++ /* Releasing the virtual group lock that was held when entering the function. */ ++ mali_group_unlock(group); ++ ++ /* Start a physical job (if we acquired a physical group earlier). */ ++ if (NULL != physical_job && NULL != physical_group) { ++ mali_group_lock(physical_group); ++ ++ /* Change the group state from LEAVING_VIRTUAL to IDLE to complete the transition. */ ++ physical_group->state = MALI_GROUP_STATE_IDLE; ++ ++ /* Start job. */ ++ mali_group_start_pp_job(physical_group, physical_job, physical_sub_job); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n", ++ mali_pp_job_get_id(physical_job), physical_job, physical_sub_job + 1, ++ mali_pp_job_get_sub_job_count(physical_job))); ++ ++ mali_group_unlock(physical_group); ++ } ++ } else { ++ /* Physical group. */ ++ struct mali_pp_job *job = NULL; ++ u32 sub_job = 0; ++ ++ job = mali_pp_scheduler_get_physical_job(); ++ if (NULL != job) { ++ /* There is a runnable physical job. */ ++ MALI_DEBUG_ASSERT(mali_pp_job_has_unstarted_sub_jobs(job)); ++ ++ /* Mark sub job as started. */ ++ sub_job = mali_pp_job_get_first_unstarted_sub_job(job); ++ mali_pp_job_mark_sub_job_started(job, sub_job); ++ ++ /* Remove job from queue (if this was the last sub job). */ ++ mali_pp_scheduler_dequeue_physical_job(job); ++ ++ mali_pp_scheduler_unlock(); ++ ++ /* Group is already on the working list, so start the new job. */ ++ mali_group_start_pp_job(group, job, sub_job); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Physical job %u (0x%08X) part %u/%u started (from job_done).\n", ++ mali_pp_job_get_id(job), job, sub_job + 1, mali_pp_job_get_sub_job_count(job))); ++ ++ mali_group_unlock(group); ++ } else { ++ mali_pp_scheduler_set_group_idle_and_unlock(group); ++ } ++ } ++} ++ ++void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success, mali_bool in_upper_half) ++{ ++ mali_bool job_is_done = MALI_FALSE; ++ mali_bool schedule_on_group = MALI_FALSE; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) part %u/%u completed (%s).\n", ++ mali_pp_job_is_virtual(job) ? "Virtual" : "Physical", ++ mali_pp_job_get_id(job), ++ job, sub_job + 1, ++ mali_pp_job_get_sub_job_count(job), ++ success ? "success" : "failure")); ++ ++ MALI_ASSERT_GROUP_LOCKED(group); ++ mali_pp_scheduler_lock(); ++ ++ mali_pp_job_mark_sub_job_completed(job, success); ++ ++ MALI_DEBUG_ASSERT(mali_pp_job_is_virtual(job) == mali_group_is_virtual(group)); ++ ++ job_is_done = mali_pp_job_is_complete(job); ++ ++ if (job_is_done) { ++ /* Job is removed from these lists when the last sub job is scheduled. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_fb_lookup_list)); ++ ++ /* Remove job from session list. */ ++ _mali_osk_list_delinit(&job->session_list); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: All parts completed for %s job %u (0x%08X).\n", ++ mali_pp_job_is_virtual(job) ? "virtual" : "physical", ++ mali_pp_job_get_id(job), job)); ++ ++ mali_pp_scheduler_unlock(); ++ ++ /* Release tracker. If other trackers are waiting on this tracker, this could ++ * trigger activation. The returned scheduling mask can be used to determine if we ++ * have to schedule GP, PP or both. */ ++ schedule_mask = mali_timeline_tracker_release(&job->tracker); ++ ++ mali_pp_scheduler_lock(); ++ } ++ ++ if (mali_group_is_virtual(group)) { ++ /* Obey the policy. */ ++ virtual_group_state = VIRTUAL_GROUP_IDLE; ++ } ++ ++ /* If paused, then this was the last job, so wake up sleeping workers and return. */ ++ if (pause_count > 0) { ++ /* Wake up sleeping workers. Their wake-up condition is that ++ * num_slots == num_slots_idle, so unless we are done working, no ++ * threads will actually be woken up. ++ */ ++ if (!mali_group_is_virtual(group)) { ++ /* Move physical group to idle list. */ ++ _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle); ++ } ++ ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_sched_switch(mali_pp_get_hw_core_desc(group->pp_core), sched_clock(), 0, 0, 0); ++#endif ++ ++ _mali_osk_wait_queue_wake_up(pp_scheduler_working_wait_queue); ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ ++ if (job_is_done) { ++ /* Return job to user and delete it. */ ++ mali_pp_scheduler_finalize_job(job); ++ } ++ ++ /* A GP job might be queued by tracker release above, ++ * make sure GP scheduler gets a chance to schedule this (if possible) ++ */ ++ mali_scheduler_schedule_from_mask(schedule_mask & ~MALI_SCHEDULER_MASK_PP, in_upper_half); ++ ++ return; ++ } ++ ++ /* Since this group just finished running a job, we can reschedule a new job on it ++ * immediately. */ ++ ++ /* By default, don't schedule on group. */ ++ schedule_on_group = MALI_FALSE; ++ ++ if (mali_group_is_virtual(group)) { ++ /* Always schedule immediately on virtual group. */ ++ schedule_mask &= ~MALI_SCHEDULER_MASK_PP; ++ schedule_on_group = MALI_TRUE; ++ } else if (0 < job_queue.depth && (!mali_scheduler_mask_is_set(schedule_mask, MALI_SCHEDULER_MASK_PP) || _mali_osk_list_empty(&group_list_idle))) { ++ struct mali_pp_job *next_job = NULL; ++ ++ next_job = mali_pp_scheduler_get_physical_job(); ++ MALI_DEBUG_ASSERT_POINTER(next_job); ++ ++ /* If no new jobs have been queued or if this group is the only idle group, we can ++ * schedule immediately on this group, unless we are GP bound and the next job would ++ * benefit from all its sub jobs being started concurrently. */ ++ ++ if (mali_scheduler_hint_is_enabled(MALI_SCHEDULER_HINT_GP_BOUND) && mali_pp_job_is_large_and_unstarted(next_job)) { ++ /* We are GP bound and the job would benefit from all sub jobs being started ++ * concurrently. Postpone scheduling until after group has been unlocked. */ ++ schedule_mask |= MALI_SCHEDULER_MASK_PP; ++ schedule_on_group = MALI_FALSE; ++ } else { ++ /* Schedule job immediately since we are not GP bound. */ ++ schedule_mask &= ~MALI_SCHEDULER_MASK_PP; ++ schedule_on_group = MALI_TRUE; ++ } ++ } ++ ++ if (schedule_on_group) { ++ /* Schedule a new job on this group. */ ++ mali_pp_scheduler_schedule_on_group_and_unlock(group); ++ } else { ++ /* Set group idle. Will rejoin virtual group, under appropriate conditions. */ ++ mali_pp_scheduler_set_group_idle_and_unlock(group); ++ } ++ ++ if (!schedule_on_group || MALI_SCHEDULER_MASK_EMPTY != schedule_mask) { ++ if (MALI_SCHEDULER_MASK_PP & schedule_mask) { ++ /* Schedule PP directly. */ ++ mali_pp_scheduler_schedule(); ++ schedule_mask &= ~MALI_SCHEDULER_MASK_PP; ++ } ++ ++ /* Schedule other jobs that were activated. */ ++ mali_scheduler_schedule_from_mask(schedule_mask, in_upper_half); ++ } ++ ++ if (job_is_done) { ++ /* Return job to user and delete it. */ ++ mali_pp_scheduler_finalize_job(job); ++ } ++} ++ ++void mali_pp_scheduler_suspend(void) ++{ ++ mali_pp_scheduler_lock(); ++ pause_count++; /* Increment the pause_count so that no more jobs will be scheduled */ ++ mali_pp_scheduler_unlock(); ++ ++ /* Go to sleep. When woken up again (in mali_pp_scheduler_job_done), the ++ * mali_pp_scheduler_suspended() function will be called. This will return true ++ * if state is idle and pause_count > 0, so if the core is active this ++ * will not do anything. ++ */ ++ _mali_osk_wait_queue_wait_event(pp_scheduler_working_wait_queue, mali_pp_scheduler_is_suspended, NULL); ++} ++ ++void mali_pp_scheduler_resume(void) ++{ ++ mali_pp_scheduler_lock(); ++ pause_count--; /* Decrement pause_count to allow scheduling again (if it reaches 0) */ ++ mali_pp_scheduler_unlock(); ++ if (0 == pause_count) { ++ mali_pp_scheduler_schedule(); ++ } ++} ++ ++mali_timeline_point mali_pp_scheduler_submit_job(struct mali_session_data *session, struct mali_pp_job *job) ++{ ++ mali_timeline_point point; ++ u32 fb_lookup_id = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ mali_pp_scheduler_lock(); ++ ++ fb_lookup_id = mali_pp_job_get_fb_lookup_id(job); ++ MALI_DEBUG_ASSERT(MALI_PP_JOB_FB_LOOKUP_LIST_SIZE > fb_lookup_id); ++ ++ /* Adding job to the lookup list used to quickly discard writeback units of queued jobs. */ ++ _mali_osk_list_addtail(&job->session_fb_lookup_list, &session->pp_job_fb_lookup_list[fb_lookup_id]); ++ ++ mali_pp_scheduler_unlock(); ++ ++ mali_pp_scheduler_job_queued(); ++ ++ /* Add job to Timeline system. */ ++ point = mali_timeline_system_add_tracker(session->timeline_system, &job->tracker, MALI_TIMELINE_PP); ++ ++ return point; ++} ++ ++_mali_osk_errcode_t _mali_ukk_pp_start_job(void *ctx, _mali_uk_pp_start_job_s *uargs) ++{ ++ struct mali_session_data *session; ++ struct mali_pp_job *job; ++ mali_timeline_point point; ++ u32 __user *timeline_point_ptr = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(uargs); ++ MALI_DEBUG_ASSERT_POINTER(ctx); ++ ++ session = (struct mali_session_data*)ctx; ++ ++ job = mali_pp_job_create(session, uargs, mali_scheduler_get_new_id()); ++ if (NULL == job) { ++ MALI_PRINT_ERROR(("Failed to create PP job.\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ timeline_point_ptr = (u32 __user *) job->uargs.timeline_point_ptr; ++ ++ point = mali_pp_scheduler_submit_job(session, job); ++ job = NULL; ++ ++ if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) { ++ /* Let user space know that something failed after the job was started. */ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_pp_and_gp_start_job(void *ctx, _mali_uk_pp_and_gp_start_job_s *uargs) ++{ ++ struct mali_session_data *session; ++ _mali_uk_pp_and_gp_start_job_s kargs; ++ struct mali_pp_job *pp_job; ++ struct mali_gp_job *gp_job; ++ u32 __user *timeline_point_ptr = NULL; ++ mali_timeline_point point; ++ ++ MALI_DEBUG_ASSERT_POINTER(ctx); ++ MALI_DEBUG_ASSERT_POINTER(uargs); ++ ++ session = (struct mali_session_data *) ctx; ++ ++ if (0 != _mali_osk_copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_and_gp_start_job_s))) { ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ pp_job = mali_pp_job_create(session, kargs.pp_args, mali_scheduler_get_new_id()); ++ if (NULL == pp_job) { ++ MALI_PRINT_ERROR(("Failed to create PP job.\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ gp_job = mali_gp_job_create(session, kargs.gp_args, mali_scheduler_get_new_id(), mali_pp_job_get_tracker(pp_job)); ++ if (NULL == gp_job) { ++ MALI_PRINT_ERROR(("Failed to create GP job.\n")); ++ mali_pp_job_delete(pp_job); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ timeline_point_ptr = (u32 __user *) pp_job->uargs.timeline_point_ptr; ++ ++ /* Submit GP job. */ ++ mali_gp_scheduler_submit_job(session, gp_job); ++ gp_job = NULL; ++ ++ /* Submit PP job. */ ++ point = mali_pp_scheduler_submit_job(session, pp_job); ++ pp_job = NULL; ++ ++ if (0 != _mali_osk_put_user(((u32) point), timeline_point_ptr)) { ++ /* Let user space know that something failed after the jobs were started. */ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores(_mali_uk_get_pp_number_of_cores_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_DEBUG_ASSERT_POINTER(args->ctx); ++ args->number_of_total_cores = num_cores; ++ args->number_of_enabled_cores = enabled_cores; ++ return _MALI_OSK_ERR_OK; ++} ++ ++u32 mali_pp_scheduler_get_num_cores_total(void) ++{ ++ return num_cores; ++} ++ ++u32 mali_pp_scheduler_get_num_cores_enabled(void) ++{ ++ return enabled_cores; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_pp_core_version(_mali_uk_get_pp_core_version_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_DEBUG_ASSERT_POINTER(args->ctx); ++ args->version = pp_version; ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args) ++{ ++ struct mali_session_data *session; ++ struct mali_pp_job *job; ++ struct mali_pp_job *tmp; ++ u32 fb_lookup_id; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_DEBUG_ASSERT_POINTER(args->ctx); ++ ++ session = (struct mali_session_data*)args->ctx; ++ ++ fb_lookup_id = args->fb_id & MALI_PP_JOB_FB_LOOKUP_LIST_MASK; ++ ++ mali_pp_scheduler_lock(); ++ ++ /* Iterate over all jobs for given frame builder_id. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &session->pp_job_fb_lookup_list[fb_lookup_id], struct mali_pp_job, session_fb_lookup_list) { ++ MALI_DEBUG_CODE(u32 disable_mask = 0); ++ ++ if (mali_pp_job_get_frame_builder_id(job) == (u32) args->fb_id) { ++ MALI_DEBUG_CODE(disable_mask |= 0xD<<(4*3)); ++ if (args->wb0_memory == job->uargs.wb0_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) { ++ MALI_DEBUG_CODE(disable_mask |= 0x1<<(4*1)); ++ mali_pp_job_disable_wb0(job); ++ } ++ if (args->wb1_memory == job->uargs.wb1_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) { ++ MALI_DEBUG_CODE(disable_mask |= 0x2<<(4*2)); ++ mali_pp_job_disable_wb1(job); ++ } ++ if (args->wb2_memory == job->uargs.wb2_registers[MALI200_REG_ADDR_WB_SOURCE_ADDR/sizeof(u32)]) { ++ MALI_DEBUG_CODE(disable_mask |= 0x3<<(4*3)); ++ mali_pp_job_disable_wb2(job); ++ } ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disable WB: 0x%X.\n", disable_mask)); ++ } else { ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Disable WB mismatching FB.\n")); ++ } ++ } ++ ++ mali_pp_scheduler_unlock(); ++} ++ ++void mali_pp_scheduler_abort_session(struct mali_session_data *session) ++{ ++ u32 i = 0; ++ struct mali_pp_job *job, *tmp_job; ++ struct mali_group *group, *tmp_group; ++ struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS]; ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(removed_jobs); ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT(session->is_aborting); ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborting all jobs from session 0x%08X.\n", session)); ++ ++ mali_pp_scheduler_lock(); ++ ++ /* Find all jobs from the aborting session. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &session->pp_job_list, struct mali_pp_job, session_list) { ++ /* Remove job from queue. */ ++ if (mali_pp_job_is_virtual(job)) { ++ MALI_DEBUG_ASSERT(1 == mali_pp_job_get_sub_job_count(job)); ++ if (0 == mali_pp_job_get_first_unstarted_sub_job(job)) { ++ --virtual_job_queue.depth; ++ } ++ } else { ++ job_queue.depth -= mali_pp_job_get_sub_job_count(job) - mali_pp_job_get_first_unstarted_sub_job(job); ++ } ++ ++ _mali_osk_list_delinit(&job->list); ++ _mali_osk_list_delinit(&job->session_fb_lookup_list); ++ ++ mali_pp_job_mark_unstarted_failed(job); ++ ++ if (mali_pp_job_is_complete(job)) { ++ /* Job is complete, remove from session list. */ ++ _mali_osk_list_delinit(&job->session_list); ++ ++ /* Move job to local list for release and deletion. */ ++ _mali_osk_list_add(&job->list, &removed_jobs); ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Aborted PP job %u (0x%08X).\n", mali_pp_job_get_id(job), job)); ++ } else { ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Keeping partially started PP job %u (0x%08X) in session.\n", mali_pp_job_get_id(job), job)); ++ } ++ } ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_working, struct mali_group, pp_scheduler_list) { ++ groups[i++] = group; ++ } ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, tmp_group, &group_list_idle, struct mali_group, pp_scheduler_list) { ++ groups[i++] = group; ++ } ++ ++ mali_pp_scheduler_unlock(); ++ ++ /* Release and delete all found jobs from the aborting session. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp_job, &removed_jobs, struct mali_pp_job, list) { ++ mali_timeline_tracker_release(&job->tracker); ++ mali_pp_job_delete(job); ++ mali_pp_scheduler_job_completed(); ++ } ++ ++ /* Abort any running jobs from the session. */ ++ while (i > 0) { ++ mali_group_abort_session(groups[--i], session); ++ } ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_abort_session(virtual_group, session); ++ } ++} ++ ++static mali_bool mali_pp_scheduler_is_suspended(void *data) ++{ ++ mali_bool ret; ++ ++ /* This callback does not use the data pointer. */ ++ MALI_IGNORE(data); ++ ++ mali_pp_scheduler_lock(); ++ ++ ret = pause_count > 0 ++ && _mali_osk_list_empty(&group_list_working) ++ && VIRTUAL_GROUP_WORKING != virtual_group_state; ++ ++ mali_pp_scheduler_unlock(); ++ ++ return ret; ++} ++ ++struct mali_pp_core *mali_pp_scheduler_get_virtual_pp(void) ++{ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ return mali_group_get_pp_core(virtual_group); ++ } else { ++ return NULL; ++ } ++} ++ ++#if MALI_STATE_TRACKING ++u32 mali_pp_scheduler_dump_state(char *buf, u32 size) ++{ ++ int n = 0; ++ struct mali_group *group; ++ struct mali_group *temp; ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "PP:\n"); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tQueue is %s\n", _mali_osk_list_empty(&job_queue.normal_pri) ? "empty" : "not empty"); ++ n += _mali_osk_snprintf(buf + n, size - n, "\tHigh priority queue is %s\n", _mali_osk_list_empty(&job_queue.high_pri) ? "empty" : "not empty"); ++ n += _mali_osk_snprintf(buf + n, size - n, "\n"); ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) { ++ n += mali_group_dump_state(group, buf + n, size - n); ++ } ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) { ++ n += mali_group_dump_state(group, buf + n, size - n); ++ } ++ ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_disabled, struct mali_group, pp_scheduler_list) { ++ n += mali_group_dump_state(group, buf + n, size - n); ++ } ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ n += mali_group_dump_state(virtual_group, buf + n, size -n); ++ } ++ ++ n += _mali_osk_snprintf(buf + n, size - n, "\n"); ++ return n; ++} ++#endif ++ ++/* This function is intended for power on reset of all cores. ++ * No locking is done for the list iteration, which can only be safe if the ++ * scheduler is paused and all cores idle. That is always the case on init and ++ * power on. */ ++void mali_pp_scheduler_reset_all_groups(void) ++{ ++ struct mali_group *group, *temp; ++ struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS]; ++ s32 i = 0; ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_lock(virtual_group); ++ mali_group_reset(virtual_group); ++ mali_group_unlock(virtual_group); ++ } ++ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working)); ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state); ++ mali_pp_scheduler_lock(); ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_idle, struct mali_group, pp_scheduler_list) { ++ groups[i++] = group; ++ } ++ mali_pp_scheduler_unlock(); ++ ++ while (i > 0) { ++ group = groups[--i]; ++ ++ mali_group_lock(group); ++ mali_group_reset(group); ++ mali_group_unlock(group); ++ } ++} ++ ++void mali_pp_scheduler_zap_all_active(struct mali_session_data *session) ++{ ++ struct mali_group *group, *temp; ++ struct mali_group *groups[MALI_MAX_NUMBER_OF_GROUPS]; ++ s32 i = 0; ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_zap_session(virtual_group, session); ++ } ++ ++ mali_pp_scheduler_lock(); ++ _MALI_OSK_LIST_FOREACHENTRY(group, temp, &group_list_working, struct mali_group, pp_scheduler_list) { ++ groups[i++] = group; ++ } ++ mali_pp_scheduler_unlock(); ++ ++ while (i > 0) { ++ mali_group_zap_session(groups[--i], session); ++ } ++} ++ ++/* A pm reference must be taken with _mali_osk_pm_dev_ref_add_no_power_on ++ * before calling this function to avoid Mali powering down as HW is accessed. ++ */ ++static void mali_pp_scheduler_enable_group_internal(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ mali_group_lock(group); ++ ++ if (MALI_GROUP_STATE_DISABLED != group->state) { ++ mali_group_unlock(group); ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already enabled.\n", group)); ++ return; ++ } ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Enabling PP group %p.\n", group)); ++ ++ mali_pp_scheduler_lock(); ++ ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state); ++ ++enabled_cores; ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_bool update_hw; ++ ++ /* Add group to virtual group. */ ++ _mali_osk_list_delinit(&(group->pp_scheduler_list)); ++ group->state = MALI_GROUP_STATE_JOINING_VIRTUAL; ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ ++ mali_group_lock(virtual_group); ++ ++ update_hw = mali_pm_is_power_on(); ++ /* Get ref of group domain */ ++ mali_group_get_pm_domain_ref(group); ++ ++ MALI_DEBUG_ASSERT(NULL == group->pm_domain || ++ MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain)); ++ ++ if (update_hw) { ++ mali_group_lock(group); ++ mali_group_power_on_group(group); ++ mali_group_reset(group); ++ mali_group_unlock(group); ++ } ++ ++ mali_pp_scheduler_enable_empty_virtual(); ++ mali_group_add_group(virtual_group, group, update_hw); ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Added to virtual group.\n", group)); ++ ++ mali_group_unlock(virtual_group); ++ } else { ++ /* Get ref of group domain */ ++ mali_group_get_pm_domain_ref(group); ++ ++ MALI_DEBUG_ASSERT(NULL == group->pm_domain || ++ MALI_PM_DOMAIN_ON == mali_pm_domain_state_get(group->pm_domain)); ++ ++ /* Put group on idle list. */ ++ if (mali_pm_is_power_on()) { ++ mali_group_power_on_group(group); ++ mali_group_reset(group); ++ } ++ ++ _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_idle); ++ group->state = MALI_GROUP_STATE_IDLE; ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Done enabling group %p. Now on idle list.\n", group)); ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++ } ++} ++ ++void mali_pp_scheduler_enable_group(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ ++ mali_pp_scheduler_enable_group_internal(group); ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ ++ /* Pick up any jobs that might have been queued if all PP groups were disabled. */ ++ mali_pp_scheduler_schedule(); ++} ++ ++static void mali_pp_scheduler_disable_group_internal(struct mali_group *group) ++{ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ mali_group_lock(virtual_group); ++ ++ MALI_DEBUG_ASSERT(VIRTUAL_GROUP_WORKING != virtual_group_state); ++ if (MALI_GROUP_STATE_JOINING_VIRTUAL == group->state) { ++ /* The group was in the process of being added to the virtual group. We ++ * only need to change the state to reverse this. */ ++ group->state = MALI_GROUP_STATE_LEAVING_VIRTUAL; ++ } else if (MALI_GROUP_STATE_IN_VIRTUAL == group->state) { ++ /* Remove group from virtual group. The state of the group will be ++ * LEAVING_VIRTUAL and the group will not be on any scheduler list. */ ++ mali_group_remove_group(virtual_group, group); ++ ++ mali_pp_scheduler_disable_empty_virtual(); ++ } ++ ++ mali_group_unlock(virtual_group); ++ } ++ ++ mali_group_lock(group); ++ mali_pp_scheduler_lock(); ++ ++ MALI_DEBUG_ASSERT( MALI_GROUP_STATE_IDLE == group->state ++ || MALI_GROUP_STATE_LEAVING_VIRTUAL == group->state ++ || MALI_GROUP_STATE_DISABLED == group->state); ++ ++ if (MALI_GROUP_STATE_DISABLED == group->state) { ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: PP group %p already disabled.\n", group)); ++ } else { ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: Disabling PP group %p.\n", group)); ++ ++ --enabled_cores; ++ _mali_osk_list_move(&(group->pp_scheduler_list), &group_list_disabled); ++ group->state = MALI_GROUP_STATE_DISABLED; ++ ++ mali_group_power_off_group(group, MALI_TRUE); ++ mali_group_put_pm_domain_ref(group); ++ } ++ ++ mali_pp_scheduler_unlock(); ++ mali_group_unlock(group); ++} ++ ++void mali_pp_scheduler_disable_group(struct mali_group *group) ++{ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ mali_pp_scheduler_suspend(); ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ ++ mali_pp_scheduler_disable_group_internal(group); ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ ++ mali_pp_scheduler_resume(); ++} ++ ++static void mali_pp_scheduler_notify_core_change(u32 num_cores) ++{ ++ mali_bool done = MALI_FALSE; ++ ++ if (mali_is_mali450()) { ++ return; ++ } ++ ++ /* ++ * This function gets a bit complicated because we can't hold the session lock while ++ * allocating notification objects. ++ */ ++ ++ while (!done) { ++ u32 i; ++ u32 num_sessions_alloc; ++ u32 num_sessions_with_lock; ++ u32 used_notification_objects = 0; ++ _mali_osk_notification_t **notobjs; ++ ++ /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */ ++ num_sessions_alloc = mali_session_get_count(); ++ if (0 == num_sessions_alloc) { ++ /* No sessions to report to */ ++ return; ++ } ++ ++ notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc); ++ if (NULL == notobjs) { ++ MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n")); ++ /* there is probably no point in trying again, system must be really low on memory and probably unusable now anyway */ ++ return; ++ } ++ ++ for (i = 0; i < num_sessions_alloc; i++) { ++ notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_PP_NUM_CORE_CHANGE, sizeof(_mali_uk_pp_num_cores_changed_s)); ++ if (NULL != notobjs[i]) { ++ _mali_uk_pp_num_cores_changed_s *data = notobjs[i]->result_buffer; ++ data->number_of_enabled_cores = num_cores; ++ } else { ++ MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure %u)\n", i)); ++ } ++ } ++ ++ mali_session_lock(); ++ ++ /* number of sessions will not change while we hold the lock */ ++ num_sessions_with_lock = mali_session_get_count(); ++ ++ if (num_sessions_alloc >= num_sessions_with_lock) { ++ /* We have allocated enough notification objects for all the sessions atm */ ++ struct mali_session_data *session, *tmp; ++ MALI_SESSION_FOREACH(session, tmp, link) { ++ MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc); ++ if (NULL != notobjs[used_notification_objects]) { ++ mali_session_send_notification(session, notobjs[used_notification_objects]); ++ notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */ ++ } ++ used_notification_objects++; ++ } ++ done = MALI_TRUE; ++ } ++ ++ mali_session_unlock(); ++ ++ /* Delete any remaining/unused notification objects */ ++ for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) { ++ if (NULL != notobjs[used_notification_objects]) { ++ _mali_osk_notification_delete(notobjs[used_notification_objects]); ++ } ++ } ++ ++ _mali_osk_free(notobjs); ++ } ++} ++ ++static void mali_pp_scheduler_core_scale_up(unsigned int target_core_nr) ++{ ++ MALI_DEBUG_PRINT(2, ("Requesting %d cores: enabling %d cores\n", target_core_nr, target_core_nr - enabled_cores)); ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ _mali_osk_pm_dev_barrier(); ++ ++ while (target_core_nr > enabled_cores) { ++ /* ++ * If there are any cores which do not belong to any domain, ++ * then these will always be found at the head of the list and ++ * we'll thus enabled these first. ++ */ ++ ++ mali_pp_scheduler_lock(); ++ ++ if (!_mali_osk_list_empty(&group_list_disabled)) { ++ struct mali_group *group; ++ ++ group = _MALI_OSK_LIST_ENTRY(group_list_disabled.next, struct mali_group, pp_scheduler_list); ++ ++ MALI_DEBUG_ASSERT_POINTER(group); ++ MALI_DEBUG_ASSERT(MALI_GROUP_STATE_DISABLED == group->state); ++ ++ mali_pp_scheduler_unlock(); ++ ++ mali_pp_scheduler_enable_group_internal(group); ++ } else { ++ mali_pp_scheduler_unlock(); ++ break; /* no more groups on disabled list */ ++ } ++ } ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ ++ mali_pp_scheduler_schedule(); ++} ++ ++static void mali_pp_scheduler_core_scale_down(unsigned int target_core_nr) ++{ ++ MALI_DEBUG_PRINT(2, ("Requesting %d cores: disabling %d cores\n", target_core_nr, enabled_cores - target_core_nr)); ++ ++ mali_pp_scheduler_suspend(); ++ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&group_list_working)); ++ ++ _mali_osk_pm_dev_ref_add_no_power_on(); ++ ++ if (NULL != mali_pmu_get_global_pmu_core()) { ++ int i; ++ ++ for (i = MALI_MAX_NUMBER_OF_DOMAINS - 1; i >= 0; i--) { ++ if (target_core_nr < enabled_cores) { ++ struct mali_pm_domain *domain; ++ ++ domain = mali_pm_domain_get_from_index(i); ++ ++ /* Domain is valid and has pp cores */ ++ if ((NULL != domain) && (NULL != domain->group_list)) { ++ struct mali_group *group; ++ ++ MALI_PM_DOMAIN_FOR_EACH_GROUP(group, domain) { ++ /* If group is pp core */ ++ if (NULL != mali_group_get_pp_core(group)) { ++ mali_pp_scheduler_disable_group_internal(group); ++ if (target_core_nr >= enabled_cores) { ++ break; ++ } ++ } ++ } ++ } ++ } else { ++ break; ++ } ++ } ++ } ++ ++ /* ++ * Didn't find enough cores associated with a power domain, ++ * so we need to disable cores which we can't power off with the PMU. ++ * Start with physical groups used by the scheduler, ++ * then remove physical from virtual if even more groups are needed. ++ */ ++ ++ while (target_core_nr < enabled_cores) { ++ mali_pp_scheduler_lock(); ++ if (!_mali_osk_list_empty(&group_list_idle)) { ++ struct mali_group *group; ++ ++ group = _MALI_OSK_LIST_ENTRY(group_list_idle.next, struct mali_group, pp_scheduler_list); ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ mali_pp_scheduler_unlock(); ++ ++ mali_pp_scheduler_disable_group_internal(group); ++ } else { ++ mali_pp_scheduler_unlock(); ++ break; /* No more physical groups */ ++ } ++ } ++ ++ if (mali_pp_scheduler_has_virtual_group()) { ++ while (target_core_nr < enabled_cores) { ++ mali_group_lock(virtual_group); ++ if (!_mali_osk_list_empty(&virtual_group->group_list)) { ++ struct mali_group *group; ++ ++ group = _MALI_OSK_LIST_ENTRY(virtual_group->group_list.next, struct mali_group, group_list); ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ mali_group_unlock(virtual_group); ++ ++ mali_pp_scheduler_disable_group_internal(group); ++ } else { ++ mali_group_unlock(virtual_group); ++ break; /* No more physical groups in virtual group */ ++ } ++ } ++ } ++ ++ _mali_osk_pm_dev_ref_dec_no_power_on(); ++ ++ mali_pp_scheduler_resume(); ++} ++ ++int mali_pp_scheduler_set_perf_level(unsigned int target_core_nr, mali_bool override) ++{ ++ if (target_core_nr == enabled_cores) return 0; ++ if (MALI_FALSE == core_scaling_enabled && MALI_FALSE == override) return -EPERM; ++ if (target_core_nr > num_cores) return -EINVAL; ++ if (0 == target_core_nr) return -EINVAL; ++ ++ if (target_core_nr > enabled_cores) { ++ mali_pp_scheduler_core_scale_up(target_core_nr); ++ } else if (target_core_nr < enabled_cores) { ++ mali_pp_scheduler_core_scale_down(target_core_nr); ++ } ++ ++ if (target_core_nr != enabled_cores) { ++ MALI_DEBUG_PRINT(2, ("Core scaling failed, target number: %d, actual number: %d\n", target_core_nr, enabled_cores)); ++ } ++ ++ mali_pp_scheduler_notify_core_change(enabled_cores); ++ ++ return 0; ++} ++ ++void mali_pp_scheduler_core_scaling_enable(void) ++{ ++ /* PS: Core scaling is by default enabled */ ++ core_scaling_enabled = MALI_TRUE; ++} ++ ++void mali_pp_scheduler_core_scaling_disable(void) ++{ ++ core_scaling_enabled = MALI_FALSE; ++} ++ ++mali_bool mali_pp_scheduler_core_scaling_is_enabled(void) ++{ ++ return core_scaling_enabled; ++} ++ ++static void mali_pp_scheduler_job_queued(void) ++{ ++ /* We hold a PM reference for every job we hold queued (and running) */ ++ _mali_osk_pm_dev_ref_add(); ++ ++ if (mali_utilization_enabled()) { ++ /* ++ * We cheat a little bit by counting the PP as busy from the time a PP job is queued. ++ * This will be fine because we only loose the tiny idle gap between jobs, but ++ * we will instead get less utilization work to do (less locks taken) ++ */ ++ mali_utilization_pp_start(); ++ } ++} ++ ++static void mali_pp_scheduler_job_completed(void) ++{ ++ /* Release the PM reference we got in the mali_pp_scheduler_job_queued() function */ ++ _mali_osk_pm_dev_ref_dec(); ++ ++ if (mali_utilization_enabled()) { ++ mali_utilization_pp_end(); ++ } ++} ++ ++static void mali_pp_scheduler_abort_job_and_unlock_scheduler(struct mali_pp_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock); ++ ++ /* This job should not be on any lists. */ ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->list)); ++ MALI_DEBUG_ASSERT(_mali_osk_list_empty(&job->session_list)); ++ ++ _mali_osk_list_delinit(&job->session_fb_lookup_list); ++ ++ mali_pp_scheduler_unlock(); ++ ++ /* Release tracker. */ ++ mali_timeline_tracker_release(&job->tracker); ++} ++ ++static mali_scheduler_mask mali_pp_scheduler_queue_job(struct mali_pp_job *job) ++{ ++ _mali_osk_list_t *queue = NULL; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ struct mali_pp_job *iter, *tmp; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->session); ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ if (mali_pp_job_needs_dma_buf_mapping(job)) { ++ mali_dma_buf_map_job(job); ++ } ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++ mali_pp_scheduler_lock(); ++ ++ if (unlikely(job->session->is_aborting)) { ++ /* Before checking if the session is aborting, the scheduler must be locked. */ ++ MALI_DEBUG_ASSERT_LOCK_HELD(pp_scheduler_lock); ++ ++ MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) queued while session is aborting.\n", mali_pp_job_get_id(job), job)); ++ ++ mali_pp_scheduler_abort_job_and_unlock_scheduler(job); ++ ++ /* Delete job. */ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) ++ mali_pp_scheduler_deferred_job_delete(job); ++#else ++ mali_pp_job_delete(job); ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_DELETE) */ ++ mali_pp_scheduler_job_completed(); ++ ++ /* Since we are aborting we ignore the scheduler mask. */ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++ ++#if defined(CONFIG_GPU_TRACEPOINTS) && defined(CONFIG_TRACEPOINTS) ++ trace_gpu_job_enqueue(mali_pp_job_get_tid(job), mali_pp_job_get_id(job), "PP"); ++#endif ++ ++ _mali_osk_profiling_add_event(MALI_PROFILING_EVENT_TYPE_SINGLE | MALI_PROFILING_EVENT_CHANNEL_SOFTWARE | MALI_PROFILING_EVENT_REASON_SINGLE_SW_PP_ENQUEUE, job->pid, job->tid, job->uargs.frame_builder_id, job->uargs.flush_id, 0); ++ ++ job->cache_order = mali_scheduler_get_new_cache_order(); ++ ++ /* Determine which queue the job should be added to. */ ++ if (mali_pp_job_is_virtual(job)) { ++ if (job->session->use_high_priority_job_queue) { ++ queue = &virtual_job_queue.high_pri; ++ } else { ++ queue = &virtual_job_queue.normal_pri; ++ } ++ ++ virtual_job_queue.depth += 1; ++ ++ /* Set schedule bitmask if the virtual group is idle. */ ++ if (VIRTUAL_GROUP_IDLE == virtual_group_state) { ++ schedule_mask |= MALI_SCHEDULER_MASK_PP; ++ } ++ } else { ++ if (job->session->use_high_priority_job_queue) { ++ queue = &job_queue.high_pri; ++ } else { ++ queue = &job_queue.normal_pri; ++ } ++ ++ job_queue.depth += mali_pp_job_get_sub_job_count(job); ++ ++ /* Set schedule bitmask if there are physical PP cores available, or if there is an ++ * idle virtual group. */ ++ if (!_mali_osk_list_empty(&group_list_idle) ++ || (mali_pp_scheduler_has_virtual_group() ++ && (VIRTUAL_GROUP_IDLE == virtual_group_state))) { ++ schedule_mask |= MALI_SCHEDULER_MASK_PP; ++ } ++ } ++ ++ /* Find position in queue where job should be added. */ ++ _MALI_OSK_LIST_FOREACHENTRY_REVERSE(iter, tmp, queue, struct mali_pp_job, list) { ++ if (mali_pp_job_should_start_after(job, iter)) { ++ break; ++ } ++ } ++ ++ /* Add job to queue. */ ++ _mali_osk_list_add(&job->list, &iter->list); ++ ++ /* Add job to session list. */ ++ _mali_osk_list_addtail(&job->session_list, &(job->session->pp_job_list)); ++ ++ MALI_DEBUG_PRINT(3, ("Mali PP scheduler: %s job %u (0x%08X) with %u parts queued.\n", ++ mali_pp_job_is_virtual(job) ? "Virtual" : "Physical", ++ mali_pp_job_get_id(job), job, mali_pp_job_get_sub_job_count(job))); ++ ++ mali_pp_scheduler_unlock(); ++ ++ return schedule_mask; ++} ++ ++mali_scheduler_mask mali_pp_scheduler_activate_job(struct mali_pp_job *job) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->session); ++ ++ MALI_DEBUG_PRINT(4, ("Mali PP scheduler: Timeline activation for job %u (0x%08X).\n", mali_pp_job_get_id(job), job)); ++ ++ if (MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT & job->tracker.activation_error) { ++ MALI_DEBUG_PRINT(2, ("Mali PP scheduler: Job %u (0x%08X) activated with error, aborting.\n", mali_pp_job_get_id(job), job)); ++ ++ mali_pp_scheduler_lock(); ++ mali_pp_scheduler_abort_job_and_unlock_scheduler(job); ++ ++ mali_pp_job_mark_sub_job_completed(job, MALI_FALSE); /* Flagging the job as failed. */ ++ mali_pp_scheduler_finalize_job(job); ++ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++ ++ /* PP job is ready to run, queue it. */ ++ ++#if defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) ++ if (mali_pp_job_needs_dma_buf_mapping(job)) { ++ mali_pp_scheduler_deferred_job_queue(job); ++ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++#endif /* defined(MALI_PP_SCHEDULER_USE_DEFERRED_JOB_QUEUE) */ ++ ++ schedule_mask = mali_pp_scheduler_queue_job(job); ++ ++ return schedule_mask; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.h +new file mode 100644 +index 0000000..e414dff +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_pp_scheduler.h +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PP_SCHEDULER_H__ ++#define __MALI_PP_SCHEDULER_H__ ++ ++#include "mali_osk.h" ++#include "mali_pp_job.h" ++#include "mali_group.h" ++#include "linux/mali/mali_utgard.h" ++ ++/** Initalize the HW independent parts of the PP scheduler ++ */ ++_mali_osk_errcode_t mali_pp_scheduler_initialize(void); ++void mali_pp_scheduler_terminate(void); ++ ++/** Poplulate the PP scheduler with groups ++ */ ++void mali_pp_scheduler_populate(void); ++void mali_pp_scheduler_depopulate(void); ++ ++/** ++ * @brief Handle job completion. ++ * ++ * Will attempt to start a new job on the locked group. ++ * ++ * If all sub jobs have completed the job's tracker will be released, any other resources associated ++ * with the job will be freed. A notification will also be sent to user space. ++ * ++ * Releasing the tracker might activate other jobs, so if appropriate we also schedule them. ++ * ++ * @note Group must be locked when entering this function. Will be unlocked before exiting. ++ * ++ * @param group The group that completed the job. ++ * @param job The job that is done. ++ * @param sub_job Sub job of job. ++ * @param success MALI_TRUE if job completed successfully, MALI_FALSE if not. ++ * @param in_upper_half MALI_TRUE if called from upper half, MALI_FALSE if not. ++ */ ++void mali_pp_scheduler_job_done(struct mali_group *group, struct mali_pp_job *job, u32 sub_job, mali_bool success, mali_bool in_upper_half); ++ ++void mali_pp_scheduler_suspend(void); ++void mali_pp_scheduler_resume(void); ++ ++/** ++ * @brief Abort all running and queued PP jobs from session. ++ * ++ * This functions aborts all PP jobs from the specified session. Queued jobs are removed from the ++ * queue and jobs currently running on a core will be aborted. ++ * ++ * @param session Session that is aborting. ++ */ ++void mali_pp_scheduler_abort_session(struct mali_session_data *session); ++ ++/** ++ * @brief Reset all groups ++ * ++ * This function resets all groups known by the PP scheuduler. This must be ++ * called after the Mali HW has been powered on in order to reset the HW. ++ * ++ * This function is intended for power on reset of all cores. ++ * No locking is done, which can only be safe if the scheduler is paused and ++ * all cores idle. That is always the case on init and power on. ++ */ ++void mali_pp_scheduler_reset_all_groups(void); ++ ++/** ++ * @brief Zap TLB on all groups with \a session active ++ * ++ * The scheculer will zap the session on all groups it owns. ++ */ ++void mali_pp_scheduler_zap_all_active(struct mali_session_data *session); ++ ++/** ++ * @brief Get the virtual PP core ++ * ++ * The returned PP core may only be used to prepare DMA command buffers for the ++ * PP core. Other actions must go through the PP scheduler, or the virtual ++ * group. ++ * ++ * @return Pointer to the virtual PP core, NULL if this doesn't exist ++ */ ++struct mali_pp_core *mali_pp_scheduler_get_virtual_pp(void); ++ ++u32 mali_pp_scheduler_dump_state(char *buf, u32 size); ++ ++void mali_pp_scheduler_enable_group(struct mali_group *group); ++void mali_pp_scheduler_disable_group(struct mali_group *group); ++ ++/** ++ * @brief Used by the Timeline system to queue a PP job. ++ * ++ * @note @ref mali_scheduler_schedule_from_mask() should be called if this function returns non-zero. ++ * ++ * @param job The PP job that is being activated. ++ * ++ * @return A scheduling bitmask that can be used to decide if scheduling is necessary after this ++ * call. ++ */ ++mali_scheduler_mask mali_pp_scheduler_activate_job(struct mali_pp_job *job); ++ ++/** ++ * @brief Schedule queued jobs on idle cores. ++ */ ++void mali_pp_scheduler_schedule(void); ++ ++int mali_pp_scheduler_set_perf_level(u32 cores, mali_bool override); ++ ++void mali_pp_scheduler_core_scaling_enable(void); ++void mali_pp_scheduler_core_scaling_disable(void); ++mali_bool mali_pp_scheduler_core_scaling_is_enabled(void); ++ ++u32 mali_pp_scheduler_get_num_cores_total(void); ++u32 mali_pp_scheduler_get_num_cores_enabled(void); ++ ++/** ++ * @brief Returns the number of Pixel Processors in the system irrespective of the context ++ * ++ * @return number of physical Pixel Processor cores in the system ++ */ ++u32 mali_pp_scheduler_get_num_cores_total(void); ++ ++#endif /* __MALI_PP_SCHEDULER_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.c +new file mode 100644 +index 0000000..1e070ce +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.c +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_scheduler.h" ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++ ++mali_bool mali_scheduler_hints[MALI_SCHEDULER_HINT_MAX]; ++ ++static _mali_osk_atomic_t mali_job_id_autonumber; ++static _mali_osk_atomic_t mali_job_cache_order_autonumber; ++ ++static _mali_osk_wq_work_t *pp_scheduler_wq_high_pri = NULL; ++static _mali_osk_wq_work_t *gp_scheduler_wq_high_pri = NULL; ++ ++static void mali_scheduler_wq_schedule_pp(void *arg) ++{ ++ MALI_IGNORE(arg); ++ ++ mali_pp_scheduler_schedule(); ++} ++ ++static void mali_scheduler_wq_schedule_gp(void *arg) ++{ ++ MALI_IGNORE(arg); ++ ++ mali_gp_scheduler_schedule(); ++} ++ ++_mali_osk_errcode_t mali_scheduler_initialize(void) ++{ ++ if ( _MALI_OSK_ERR_OK != _mali_osk_atomic_init(&mali_job_id_autonumber, 0)) { ++ MALI_DEBUG_PRINT(1, ("Initialization of atomic job id counter failed.\n")); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ if ( _MALI_OSK_ERR_OK != _mali_osk_atomic_init(&mali_job_cache_order_autonumber, 0)) { ++ MALI_DEBUG_PRINT(1, ("Initialization of atomic job cache order counter failed.\n")); ++ _mali_osk_atomic_term(&mali_job_id_autonumber); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ pp_scheduler_wq_high_pri = _mali_osk_wq_create_work_high_pri(mali_scheduler_wq_schedule_pp, NULL); ++ if (NULL == pp_scheduler_wq_high_pri) { ++ _mali_osk_atomic_term(&mali_job_cache_order_autonumber); ++ _mali_osk_atomic_term(&mali_job_id_autonumber); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ gp_scheduler_wq_high_pri = _mali_osk_wq_create_work_high_pri(mali_scheduler_wq_schedule_gp, NULL); ++ if (NULL == gp_scheduler_wq_high_pri) { ++ _mali_osk_wq_delete_work(pp_scheduler_wq_high_pri); ++ _mali_osk_atomic_term(&mali_job_cache_order_autonumber); ++ _mali_osk_atomic_term(&mali_job_id_autonumber); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_scheduler_terminate(void) ++{ ++ _mali_osk_wq_delete_work(gp_scheduler_wq_high_pri); ++ _mali_osk_wq_delete_work(pp_scheduler_wq_high_pri); ++ _mali_osk_atomic_term(&mali_job_cache_order_autonumber); ++ _mali_osk_atomic_term(&mali_job_id_autonumber); ++} ++ ++u32 mali_scheduler_get_new_id(void) ++{ ++ u32 job_id = _mali_osk_atomic_inc_return(&mali_job_id_autonumber); ++ return job_id; ++} ++ ++u32 mali_scheduler_get_new_cache_order(void) ++{ ++ u32 job_cache_order = _mali_osk_atomic_inc_return(&mali_job_cache_order_autonumber); ++ return job_cache_order; ++} ++ ++void mali_scheduler_schedule_from_mask(mali_scheduler_mask mask, mali_bool deferred_schedule) ++{ ++ if (MALI_SCHEDULER_MASK_GP & mask) { ++ /* GP needs scheduling. */ ++ if (deferred_schedule) { ++ /* Schedule GP deferred. */ ++ _mali_osk_wq_schedule_work_high_pri(gp_scheduler_wq_high_pri); ++ } else { ++ /* Schedule GP now. */ ++ mali_gp_scheduler_schedule(); ++ } ++ } ++ ++ if (MALI_SCHEDULER_MASK_PP & mask) { ++ /* PP needs scheduling. */ ++ if (deferred_schedule) { ++ /* Schedule PP deferred. */ ++ _mali_osk_wq_schedule_work_high_pri(pp_scheduler_wq_high_pri); ++ } else { ++ /* Schedule PP now. */ ++ mali_pp_scheduler_schedule(); ++ } ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.h +new file mode 100644 +index 0000000..7386053 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler.h +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_SCHEDULER_H__ ++#define __MALI_SCHEDULER_H__ ++ ++#include "mali_osk.h" ++#include "mali_scheduler_types.h" ++#include "mali_gp_scheduler.h" ++#include "mali_pp_scheduler.h" ++ ++_mali_osk_errcode_t mali_scheduler_initialize(void); ++void mali_scheduler_terminate(void); ++ ++u32 mali_scheduler_get_new_id(void); ++u32 mali_scheduler_get_new_cache_order(void); ++ ++/** ++ * @brief Reset all groups ++ * ++ * This function resets all groups known by the both the PP and GP scheuduler. ++ * This must be called after the Mali HW has been powered on in order to reset ++ * the HW. ++ */ ++MALI_STATIC_INLINE void mali_scheduler_reset_all_groups(void) ++{ ++ mali_gp_scheduler_reset_all_groups(); ++ mali_pp_scheduler_reset_all_groups(); ++} ++ ++/** ++ * @brief Zap TLB on all active groups running \a session ++ * ++ * @param session Pointer to the session to zap ++ */ ++MALI_STATIC_INLINE void mali_scheduler_zap_all_active(struct mali_session_data *session) ++{ ++ mali_gp_scheduler_zap_all_active(session); ++ mali_pp_scheduler_zap_all_active(session); ++} ++ ++/** ++ * Check if bit is set in scheduler mask. ++ * ++ * @param mask Scheduler mask to check. ++ * @param bit Bit to check. ++ * @return MALI_TRUE if bit is set in scheduler mask, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_scheduler_mask_is_set(mali_scheduler_mask mask, mali_scheduler_mask bit) ++{ ++ return MALI_SCHEDULER_MASK_EMPTY != (bit & mask); ++} ++ ++/** ++ * Schedule GP and PP according to bitmask. ++ * ++ * @param mask A scheduling bitmask. ++ * @param deferred_schedule MALI_TRUE if schedule should be deferred, MALI_FALSE if not. ++ */ ++void mali_scheduler_schedule_from_mask(mali_scheduler_mask mask, mali_bool deferred_schedule); ++ ++/* Enable or disable scheduler hint. */ ++extern mali_bool mali_scheduler_hints[MALI_SCHEDULER_HINT_MAX]; ++ ++MALI_STATIC_INLINE void mali_scheduler_hint_enable(mali_scheduler_hint hint) ++{ ++ MALI_DEBUG_ASSERT(hint < MALI_SCHEDULER_HINT_MAX); ++ mali_scheduler_hints[hint] = MALI_TRUE; ++} ++ ++MALI_STATIC_INLINE void mali_scheduler_hint_disable(mali_scheduler_hint hint) ++{ ++ MALI_DEBUG_ASSERT(hint < MALI_SCHEDULER_HINT_MAX); ++ mali_scheduler_hints[hint] = MALI_FALSE; ++} ++ ++MALI_STATIC_INLINE mali_bool mali_scheduler_hint_is_enabled(mali_scheduler_hint hint) ++{ ++ MALI_DEBUG_ASSERT(hint < MALI_SCHEDULER_HINT_MAX); ++ return mali_scheduler_hints[hint]; ++} ++ ++#endif /* __MALI_SCHEDULER_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler_types.h +new file mode 100644 +index 0000000..02490c2 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_scheduler_types.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_SCHEDULER_TYPES_H__ ++#define __MALI_SCHEDULER_TYPES_H__ ++ ++#include "mali_osk.h" ++ ++#define MALI_SCHEDULER_JOB_ID_SPAN 65535 ++ ++/** ++ * Bitmask used for defered scheduling of subsystems. ++ */ ++typedef u32 mali_scheduler_mask; ++ ++#define MALI_SCHEDULER_MASK_GP (1<<0) ++#define MALI_SCHEDULER_MASK_PP (1<<1) ++ ++#define MALI_SCHEDULER_MASK_EMPTY 0 ++#define MALI_SCHEDULER_MASK_ALL (MALI_SCHEDULER_MASK_GP | MALI_SCHEDULER_MASK_PP) ++ ++typedef enum { ++ MALI_SCHEDULER_HINT_GP_BOUND = 0 ++#define MALI_SCHEDULER_HINT_MAX 1 ++} mali_scheduler_hint; ++ ++#endif /* __MALI_SCHEDULER_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.c +new file mode 100644 +index 0000000..812dbf8 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.c +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "mali_session.h" ++ ++_MALI_OSK_LIST_HEAD(mali_sessions); ++static u32 mali_session_count = 0; ++ ++_mali_osk_spinlock_irq_t *mali_sessions_lock; ++ ++_mali_osk_errcode_t mali_session_initialize(void) ++{ ++ _MALI_OSK_INIT_LIST_HEAD(&mali_sessions); ++ ++ mali_sessions_lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SESSIONS); ++ ++ if (NULL == mali_sessions_lock) return _MALI_OSK_ERR_NOMEM; ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_session_terminate(void) ++{ ++ _mali_osk_spinlock_irq_term(mali_sessions_lock); ++} ++ ++void mali_session_add(struct mali_session_data *session) ++{ ++ mali_session_lock(); ++ _mali_osk_list_add(&session->link, &mali_sessions); ++ mali_session_count++; ++ mali_session_unlock(); ++} ++ ++void mali_session_remove(struct mali_session_data *session) ++{ ++ mali_session_lock(); ++ _mali_osk_list_delinit(&session->link); ++ mali_session_count--; ++ mali_session_unlock(); ++} ++ ++u32 mali_session_get_count(void) ++{ ++ return mali_session_count; ++} ++ ++/* ++ * Get the max completed window jobs from all active session, ++ * which will be used in window render frame per sec calculate ++ */ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++u32 mali_session_max_window_num(void) ++{ ++ struct mali_session_data *session, *tmp; ++ u32 max_window_num = 0; ++ u32 tmp_number = 0; ++ ++ mali_session_lock(); ++ ++ MALI_SESSION_FOREACH(session, tmp, link) { ++ tmp_number = _mali_osk_atomic_xchg(&session->number_of_window_jobs, 0); ++ if (max_window_num < tmp_number) { ++ max_window_num = tmp_number; ++ } ++ } ++ ++ mali_session_unlock(); ++ ++ return max_window_num; ++} ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.h +new file mode 100644 +index 0000000..0060406 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_session.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_SESSION_H__ ++#define __MALI_SESSION_H__ ++ ++#include "mali_mmu_page_directory.h" ++#include "mali_kernel_descriptor_mapping.h" ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++ ++struct mali_timeline_system; ++struct mali_soft_system; ++ ++/* Number of frame builder job lists per session. */ ++#define MALI_PP_JOB_FB_LOOKUP_LIST_SIZE 16 ++#define MALI_PP_JOB_FB_LOOKUP_LIST_MASK (MALI_PP_JOB_FB_LOOKUP_LIST_SIZE - 1) ++ ++struct mali_session_data { ++ _mali_osk_notification_queue_t * ioctl_queue; ++ ++ _mali_osk_mutex_t *memory_lock; /**< Lock protecting the vm manipulation */ ++ mali_descriptor_mapping * descriptor_mapping; /**< Mapping between userspace descriptors and our pointers */ ++ _mali_osk_list_t memory_head; /**< Track all the memory allocated in this session, for freeing on abnormal termination */ ++ ++ struct mali_page_directory *page_directory; /**< MMU page directory for this session */ ++ ++ _MALI_OSK_LIST_HEAD(link); /**< Link for list of all sessions */ ++ _MALI_OSK_LIST_HEAD(pp_job_list); /**< List of all PP jobs on this session */ ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ _mali_osk_atomic_t number_of_window_jobs; /**< Record the window jobs completed on this session in a period */ ++#endif ++ ++ _mali_osk_list_t pp_job_fb_lookup_list[MALI_PP_JOB_FB_LOOKUP_LIST_SIZE]; /**< List of PP job lists per frame builder id. Used to link jobs from same frame builder. */ ++ ++ struct mali_soft_job_system *soft_job_system; /**< Soft job system for this session. */ ++ struct mali_timeline_system *timeline_system; /**< Timeline system for this session. */ ++ ++ mali_bool is_aborting; /**< MALI_TRUE if the session is aborting, MALI_FALSE if not. */ ++ mali_bool use_high_priority_job_queue; /**< If MALI_TRUE, jobs added from this session will use the high priority job queues. */ ++}; ++ ++_mali_osk_errcode_t mali_session_initialize(void); ++void mali_session_terminate(void); ++ ++/* List of all sessions. Actual list head in mali_kernel_core.c */ ++extern _mali_osk_list_t mali_sessions; ++/* Lock to protect modification and access to the mali_sessions list */ ++extern _mali_osk_spinlock_irq_t *mali_sessions_lock; ++ ++MALI_STATIC_INLINE void mali_session_lock(void) ++{ ++ _mali_osk_spinlock_irq_lock(mali_sessions_lock); ++} ++ ++MALI_STATIC_INLINE void mali_session_unlock(void) ++{ ++ _mali_osk_spinlock_irq_unlock(mali_sessions_lock); ++} ++ ++void mali_session_add(struct mali_session_data *session); ++void mali_session_remove(struct mali_session_data *session); ++u32 mali_session_get_count(void); ++ ++#define MALI_SESSION_FOREACH(session, tmp, link) \ ++ _MALI_OSK_LIST_FOREACHENTRY(session, tmp, &mali_sessions, struct mali_session_data, link) ++ ++MALI_STATIC_INLINE struct mali_page_directory *mali_session_get_page_directory(struct mali_session_data *session) ++{ ++ return session->page_directory; ++} ++ ++MALI_STATIC_INLINE void mali_session_send_notification(struct mali_session_data *session, _mali_osk_notification_t *object) ++{ ++ _mali_osk_notification_queue_send(session->ioctl_queue, object); ++} ++ ++/* ++ * Get the max completed window jobs from all active session, ++ * which will be used in window render frame per sec calculate ++ */ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++u32 mali_session_max_window_num(void); ++#endif ++ ++#endif /* __MALI_SESSION_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.c +new file mode 100644 +index 0000000..e21f4c1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.c +@@ -0,0 +1,464 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_soft_job.h" ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_timeline.h" ++#include "mali_session.h" ++#include "mali_kernel_common.h" ++#include "mali_uk_types.h" ++#include "mali_scheduler.h" ++ ++MALI_STATIC_INLINE void mali_soft_job_system_lock(struct mali_soft_job_system *system) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ _mali_osk_spinlock_irq_lock(system->lock); ++ MALI_DEBUG_PRINT(5, ("Mali Soft Job: soft system %p lock taken\n", system)); ++ MALI_DEBUG_ASSERT(0 == system->lock_owner); ++ MALI_DEBUG_CODE(system->lock_owner = _mali_osk_get_tid()); ++} ++ ++MALI_STATIC_INLINE void mali_soft_job_system_unlock(struct mali_soft_job_system *system) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_PRINT(5, ("Mali Soft Job: releasing soft system %p lock\n", system)); ++ MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner); ++ MALI_DEBUG_CODE(system->lock_owner = 0); ++ _mali_osk_spinlock_irq_unlock(system->lock); ++} ++ ++#if defined(DEBUG) ++MALI_STATIC_INLINE void mali_soft_job_system_assert_locked(struct mali_soft_job_system *system) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT(_mali_osk_get_tid() == system->lock_owner); ++} ++#define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system) mali_soft_job_system_assert_locked(system) ++#else ++#define MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system) ++#endif /* defined(DEBUG) */ ++ ++struct mali_soft_job_system *mali_soft_job_system_create(struct mali_session_data *session) ++{ ++ u32 i; ++ struct mali_soft_job_system *system; ++ struct mali_soft_job *job; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ system = (struct mali_soft_job_system *) _mali_osk_calloc(1, sizeof(struct mali_soft_job_system)); ++ if (NULL == system) { ++ return NULL; ++ } ++ ++ system->session = session; ++ ++ system->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_SCHEDULER); ++ if (NULL == system->lock) { ++ mali_soft_job_system_destroy(system); ++ return NULL; ++ } ++ system->lock_owner = 0; ++ ++ _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_free)); ++ _MALI_OSK_INIT_LIST_HEAD(&(system->jobs_used)); ++ ++ for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) { ++ job = &(system->jobs[i]); ++ _mali_osk_list_add(&(job->system_list), &(system->jobs_free)); ++ job->system = system; ++ job->state = MALI_SOFT_JOB_STATE_FREE; ++ job->id = i; ++ } ++ ++ return system; ++} ++ ++void mali_soft_job_system_destroy(struct mali_soft_job_system *system) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ /* All jobs should be free at this point. */ ++ MALI_DEBUG_CODE( { ++ u32 i; ++ struct mali_soft_job *job; ++ ++ for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) ++ { ++ job = &(system->jobs[i]); ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state); ++ } ++ }); ++ ++ if (NULL != system) { ++ if (NULL != system->lock) { ++ _mali_osk_spinlock_irq_term(system->lock); ++ } ++ _mali_osk_free(system); ++ } ++} ++ ++static struct mali_soft_job *mali_soft_job_system_alloc_job(struct mali_soft_job_system *system) ++{ ++ struct mali_soft_job *job; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system); ++ ++ if (_mali_osk_list_empty(&(system->jobs_free))) { ++ /* No jobs available. */ ++ return NULL; ++ } ++ ++ /* Grab first job and move it to the used list. */ ++ job = _MALI_OSK_LIST_ENTRY(system->jobs_free.next, struct mali_soft_job, system_list); ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state); ++ ++ _mali_osk_list_move(&(job->system_list), &(system->jobs_used)); ++ job->state = MALI_SOFT_JOB_STATE_ALLOCATED; ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id); ++ MALI_DEBUG_ASSERT(system == job->system); ++ ++ return job; ++} ++ ++static void mali_soft_job_system_free_job(struct mali_soft_job_system *system, struct mali_soft_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_soft_job_system_lock(job->system); ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE != job->state); ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id); ++ MALI_DEBUG_ASSERT(system == job->system); ++ ++ job->state = MALI_SOFT_JOB_STATE_FREE; ++ _mali_osk_list_move(&(job->system_list), &(system->jobs_free)); ++ ++ mali_soft_job_system_unlock(job->system); ++} ++ ++MALI_STATIC_INLINE struct mali_soft_job *mali_soft_job_system_lookup_job(struct mali_soft_job_system *system, u32 job_id) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_ASSERT_SOFT_JOB_SYSTEM_LOCKED(system); ++ ++ if (job_id < MALI_MAX_NUM_SOFT_JOBS) { ++ return &system->jobs[job_id]; ++ } ++ ++ return NULL; ++} ++ ++void mali_soft_job_destroy(struct mali_soft_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->system); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: destroying soft job %u (0x%08X)\n", job->id, job)); ++ ++ if (NULL != job) { ++ if (0 < _mali_osk_atomic_dec_return(&job->refcount)) return; ++ ++ _mali_osk_atomic_term(&job->refcount); ++ ++ if (NULL != job->activated_notification) { ++ _mali_osk_notification_delete(job->activated_notification); ++ job->activated_notification = NULL; ++ } ++ ++ mali_soft_job_system_free_job(job->system, job); ++ } ++} ++ ++struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u32 user_job) ++{ ++ struct mali_soft_job *job; ++ _mali_osk_notification_t *notification = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_TYPE_USER_SIGNALED >= type); ++ ++ if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) { ++ notification = _mali_osk_notification_create(_MALI_NOTIFICATION_SOFT_ACTIVATED, sizeof(_mali_uk_soft_job_activated_s)); ++ if (unlikely(NULL == notification)) { ++ MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate notification")); ++ return NULL; ++ } ++ } ++ ++ mali_soft_job_system_lock(system); ++ ++ job = mali_soft_job_system_alloc_job(system); ++ if (NULL == job) { ++ mali_soft_job_system_unlock(system); ++ MALI_PRINT_ERROR(("Mali Soft Job: failed to allocate job")); ++ _mali_osk_notification_delete(notification); ++ return NULL; ++ } ++ ++ job->type = type; ++ job->user_job = user_job; ++ job->activated = MALI_FALSE; ++ ++ if (MALI_SOFT_JOB_TYPE_USER_SIGNALED == type) { ++ job->activated_notification = notification; ++ } ++ ++ _mali_osk_atomic_init(&job->refcount, 1); ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state); ++ MALI_DEBUG_ASSERT(system == job->system); ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_INVALID_ID != job->id); ++ ++ mali_soft_job_system_unlock(system); ++ ++ return job; ++} ++ ++mali_timeline_point mali_soft_job_start(struct mali_soft_job *job, struct mali_timeline_fence *fence) ++{ ++ mali_timeline_point point; ++ struct mali_soft_job_system *system; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ ++ MALI_DEBUG_ASSERT_POINTER(job->system); ++ system = job->system; ++ ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ MALI_DEBUG_ASSERT_POINTER(system->session->timeline_system); ++ ++ mali_soft_job_system_lock(system); ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_ALLOCATED == job->state); ++ job->state = MALI_SOFT_JOB_STATE_STARTED; ++ ++ mali_soft_job_system_unlock(system); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: starting soft job %u (0x%08X)\n", job->id, job)); ++ ++ mali_timeline_tracker_init(&job->tracker, MALI_TIMELINE_TRACKER_SOFT, fence, job); ++ point = mali_timeline_system_add_tracker(system->session->timeline_system, &job->tracker, MALI_TIMELINE_SOFT); ++ ++ return point; ++} ++ ++static mali_bool mali_soft_job_is_activated(void *data) ++{ ++ struct mali_soft_job *job; ++ ++ job = (struct mali_soft_job *) data; ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ return job->activated; ++} ++ ++_mali_osk_errcode_t mali_soft_job_system_signal_job(struct mali_soft_job_system *system, u32 job_id) ++{ ++ struct mali_soft_job *job; ++ struct mali_timeline_system *timeline_system; ++ mali_scheduler_mask schedule_mask; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_soft_job_system_lock(system); ++ ++ job = mali_soft_job_system_lookup_job(system, job_id); ++ ++ if (NULL == job || !(MALI_SOFT_JOB_STATE_STARTED == job->state || MALI_SOFT_JOB_STATE_TIMED_OUT == job->state)) { ++ mali_soft_job_system_unlock(system); ++ MALI_PRINT_ERROR(("Mali Soft Job: invalid soft job id %u", job_id)); ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) { ++ job->state = MALI_SOFT_JOB_STATE_SIGNALED; ++ mali_soft_job_system_unlock(system); ++ ++ MALI_DEBUG_ASSERT(MALI_TRUE == job->activated); ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: soft job %u (0x%08X) was timed out\n", job->id, job)); ++ mali_soft_job_destroy(job); ++ ++ return _MALI_OSK_ERR_TIMEOUT; ++ } ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state); ++ ++ job->state = MALI_SOFT_JOB_STATE_SIGNALED; ++ mali_soft_job_system_unlock(system); ++ ++ /* Since the job now is in signaled state, timeouts from the timeline system will be ++ * ignored, and it is not possible to signal this job again. */ ++ ++ timeline_system = system->session->timeline_system; ++ MALI_DEBUG_ASSERT_POINTER(timeline_system); ++ ++ /* Wait until activated. */ ++ _mali_osk_wait_queue_wait_event(timeline_system->wait_queue, mali_soft_job_is_activated, (void *) job); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: signaling soft job %u (0x%08X)\n", job->id, job)); ++ ++ schedule_mask = mali_timeline_tracker_release(&job->tracker); ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE); ++ ++ mali_soft_job_destroy(job); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++static void mali_soft_job_send_activated_notification(struct mali_soft_job *job) ++{ ++ if (NULL != job->activated_notification) { ++ _mali_uk_soft_job_activated_s *res = job->activated_notification->result_buffer; ++ res->user_job = job->user_job; ++ mali_session_send_notification(job->system->session, job->activated_notification); ++ } ++ job->activated_notification = NULL; ++} ++ ++void mali_soft_job_system_activate_job(struct mali_soft_job *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->system); ++ MALI_DEBUG_ASSERT_POINTER(job->system->session); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline activation for soft job %u (0x%08X).\n", job->id, job)); ++ ++ mali_soft_job_system_lock(job->system); ++ ++ if (unlikely(job->system->session->is_aborting)) { ++ MALI_DEBUG_PRINT(3, ("Mali Soft Job: Soft job %u (0x%08X) activated while session is aborting.\n", job->id, job)); ++ ++ mali_soft_job_system_unlock(job->system); ++ ++ /* Since we are in shutdown, we can ignore the scheduling bitmask. */ ++ mali_timeline_tracker_release(&job->tracker); ++ mali_soft_job_destroy(job); ++ return; ++ } ++ ++ /* Send activated notification. */ ++ mali_soft_job_send_activated_notification(job); ++ ++ /* Wake up sleeping signaler. */ ++ job->activated = MALI_TRUE; ++ _mali_osk_wait_queue_wake_up(job->tracker.system->wait_queue); ++ ++ mali_soft_job_system_unlock(job->system); ++} ++ ++mali_scheduler_mask mali_soft_job_system_timeout_job(struct mali_soft_job *job) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(job); ++ MALI_DEBUG_ASSERT_POINTER(job->system); ++ MALI_DEBUG_ASSERT_POINTER(job->system->session); ++ MALI_DEBUG_ASSERT(MALI_TRUE == job->activated); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeline timeout for soft job %u (0x%08X).\n", job->id, job)); ++ ++ mali_soft_job_system_lock(job->system); ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state || ++ MALI_SOFT_JOB_STATE_SIGNALED == job->state); ++ ++ if (unlikely(job->system->session->is_aborting)) { ++ /* The session is aborting. This job will be released and destroyed by @ref ++ * mali_soft_job_system_abort(). */ ++ mali_soft_job_system_unlock(job->system); ++ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++ ++ if (MALI_SOFT_JOB_STATE_STARTED != job->state) { ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state); ++ ++ /* The job is about to be signaled, ignore timeout. */ ++ MALI_DEBUG_PRINT(4, ("Mali Soft Job: Timeout on soft job %u (0x%08X) in signaled state.\n", job->id, job)); ++ mali_soft_job_system_unlock(job->system); ++ return schedule_mask; ++ } ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_STARTED == job->state); ++ ++ job->state = MALI_SOFT_JOB_STATE_TIMED_OUT; ++ _mali_osk_atomic_inc(&job->refcount); ++ ++ mali_soft_job_system_unlock(job->system); ++ ++ schedule_mask = mali_timeline_tracker_release(&job->tracker); ++ ++ mali_soft_job_destroy(job); ++ ++ return schedule_mask; ++} ++ ++void mali_soft_job_system_abort(struct mali_soft_job_system *system) ++{ ++ u32 i; ++ struct mali_soft_job *job, *tmp; ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(jobs); ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ MALI_DEBUG_ASSERT(system->session->is_aborting); ++ ++ MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting soft job system for session 0x%08X.\n", system->session)); ++ ++ mali_soft_job_system_lock(system); ++ ++ for (i = 0; i < MALI_MAX_NUM_SOFT_JOBS; ++i) { ++ job = &(system->jobs[i]); ++ ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_FREE == job->state || ++ MALI_SOFT_JOB_STATE_STARTED == job->state || ++ MALI_SOFT_JOB_STATE_TIMED_OUT == job->state); ++ ++ if (MALI_SOFT_JOB_STATE_STARTED == job->state) { ++ /* If the job has been activated, we have to release the tracker and destroy ++ * the job. If not, the tracker will be released and the job destroyed when ++ * it is activated. */ ++ if (MALI_TRUE == job->activated) { ++ MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting unsignaled soft job %u (0x%08X).\n", job->id, job)); ++ ++ job->state = MALI_SOFT_JOB_STATE_SIGNALED; ++ _mali_osk_list_move(&job->system_list, &jobs); ++ } ++ } else if (MALI_SOFT_JOB_STATE_TIMED_OUT == job->state) { ++ MALI_DEBUG_PRINT(3, ("Mali Soft Job: Aborting timed out soft job %u (0x%08X).\n", job->id, job)); ++ ++ /* We need to destroy this soft job. */ ++ _mali_osk_list_move(&job->system_list, &jobs); ++ } ++ } ++ ++ mali_soft_job_system_unlock(system); ++ ++ /* Release and destroy jobs. */ ++ _MALI_OSK_LIST_FOREACHENTRY(job, tmp, &jobs, struct mali_soft_job, system_list) { ++ MALI_DEBUG_ASSERT(MALI_SOFT_JOB_STATE_SIGNALED == job->state || ++ MALI_SOFT_JOB_STATE_TIMED_OUT == job->state); ++ ++ if (MALI_SOFT_JOB_STATE_SIGNALED == job->state) { ++ mali_timeline_tracker_release(&job->tracker); ++ } ++ ++ /* Move job back to used list before destroying. */ ++ _mali_osk_list_move(&job->system_list, &system->jobs_used); ++ ++ mali_soft_job_destroy(job); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.h +new file mode 100644 +index 0000000..af978ab +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_soft_job.h +@@ -0,0 +1,196 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_SOFT_JOB_H__ ++#define __MALI_SOFT_JOB_H__ ++ ++#include "mali_osk.h" ++ ++#include "mali_timeline.h" ++ ++struct mali_timeline_fence; ++struct mali_session_data; ++struct mali_soft_job; ++struct mali_soft_job_system; ++ ++/** ++ * Soft job types. ++ * ++ * Soft jobs of type MALI_SOFT_JOB_TYPE_USER_SIGNALED will only complete after activation if either ++ * they are signaled by user-space (@ref mali_soft_job_system_signaled_job) or if they are timed out ++ * by the Timeline system. ++ */ ++typedef enum mali_soft_job_type { ++ MALI_SOFT_JOB_TYPE_USER_SIGNALED, ++} mali_soft_job_type; ++ ++/** ++ * Soft job state. ++ * ++ * All soft jobs in a soft job system will initially be in state MALI_SOFT_JOB_STATE_FREE. On @ref ++ * mali_soft_job_system_start_job a job will first be allocated. A job in state ++ * MALI_SOFT_JOB_STATE_FREE will be picked and the state changed to MALI_SOFT_JOB_STATE_ALLOCATED. ++ * Once the job is added to the timeline system, the state changes to MALI_SOFT_JOB_STATE_STARTED. ++ * ++ * For soft jobs of type MALI_SOFT_JOB_TYPE_USER_SIGNALED the state is changed to ++ * MALI_SOFT_JOB_STATE_SIGNALED when @ref mali_soft_job_system_signal_job is called and the soft ++ * job's state is MALI_SOFT_JOB_STATE_STARTED or MALI_SOFT_JOB_STATE_TIMED_OUT. ++ * ++ * If a soft job of type MALI_SOFT_JOB_TYPE_USER_SIGNALED is timed out before being signaled, the ++ * state is changed to MALI_SOFT_JOB_STATE_TIMED_OUT. This can only happen to soft jobs in state ++ * MALI_SOFT_JOB_STATE_STARTED. ++ * ++ * When a soft job's reference count reaches zero, it will be freed and the state returns to ++ * MALI_SOFT_JOB_STATE_FREE. ++ */ ++typedef enum mali_soft_job_state { ++ MALI_SOFT_JOB_STATE_FREE, ++ MALI_SOFT_JOB_STATE_ALLOCATED, ++ MALI_SOFT_JOB_STATE_STARTED, ++ MALI_SOFT_JOB_STATE_SIGNALED, ++ MALI_SOFT_JOB_STATE_TIMED_OUT, ++} mali_soft_job_state; ++ ++#define MALI_SOFT_JOB_INVALID_ID ((u32) -1) ++ ++/* Maximum number of soft jobs per soft system. */ ++#define MALI_MAX_NUM_SOFT_JOBS 20 ++ ++/** ++ * Soft job struct. ++ * ++ * Soft job can be used to represent any kind of CPU work done in kernel-space. ++ */ ++typedef struct mali_soft_job { ++ mali_soft_job_type type; /**< Soft job type. Must be one of MALI_SOFT_JOB_TYPE_*. */ ++ u32 user_job; /**< Identifier for soft job in user space. */ ++ _mali_osk_atomic_t refcount; /**< Soft jobs are reference counted to prevent premature deletion. */ ++ struct mali_timeline_tracker tracker; /**< Timeline tracker for soft job. */ ++ mali_bool activated; /**< MALI_TRUE if the job has been activated, MALI_FALSE if not. */ ++ _mali_osk_notification_t *activated_notification; /**< Pre-allocated notification object for ACTIVATED_NOTIFICATION. */ ++ ++ /* Protected by soft job system lock. */ ++ u32 id; /**< Used by user-space to find corresponding soft job in kernel-space. */ ++ mali_soft_job_state state; /**< State of soft job, must be one of MALI_SOFT_JOB_STATE_*. */ ++ struct mali_soft_job_system *system; /**< The soft job system this job is in. */ ++ _mali_osk_list_t system_list; /**< List element used by soft job system. */ ++} mali_soft_job; ++ ++/** ++ * Per-session soft job system. ++ * ++ * The soft job system is used to manage all soft jobs that belongs to a session. ++ */ ++typedef struct mali_soft_job_system { ++ struct mali_session_data *session; /**< The session this soft job system belongs to. */ ++ ++ struct mali_soft_job jobs[MALI_MAX_NUM_SOFT_JOBS]; /**< Array of all soft jobs in this system. */ ++ _MALI_OSK_LIST_HEAD(jobs_free); /**< List of all free soft jobs. */ ++ _MALI_OSK_LIST_HEAD(jobs_used); /**< List of all allocated soft jobs. */ ++ ++ _mali_osk_spinlock_irq_t *lock; /**< Lock used to protect soft job system and its soft jobs. */ ++ u32 lock_owner; /**< Contains tid of thread that locked the system or 0, if not locked. */ ++} mali_soft_job_system; ++ ++/** ++ * Create a soft job system. ++ * ++ * @param session The session this soft job system will belong to. ++ * @return The new soft job system, or NULL if unsuccessful. ++ */ ++struct mali_soft_job_system *mali_soft_job_system_create(struct mali_session_data *session); ++ ++/** ++ * Destroy a soft job system. ++ * ++ * @note The soft job must not have any started or activated jobs. Call @ref ++ * mali_soft_job_system_abort first. ++ * ++ * @param system The soft job system we are destroying. ++ */ ++void mali_soft_job_system_destroy(struct mali_soft_job_system *system); ++ ++/** ++ * Create a soft job. ++ * ++ * @param system Soft job system to create soft job from. ++ * @param type Type of the soft job. ++ * @param user_job Identifier for soft job in user space. ++ * @return New soft job if successful, NULL if not. ++ */ ++struct mali_soft_job *mali_soft_job_create(struct mali_soft_job_system *system, mali_soft_job_type type, u32 user_job); ++ ++/** ++ * Destroy soft job. ++ * ++ * @param job Soft job to destroy. ++ */ ++void mali_soft_job_destroy(struct mali_soft_job *job); ++ ++/** ++ * Start a soft job. ++ * ++ * The soft job will be added to the Timeline system which will then activate it after all ++ * dependencies have been resolved. ++ * ++ * Create soft jobs with @ref mali_soft_job_create before starting them. ++ * ++ * @param job Soft job to start. ++ * @param fence Fence representing dependencies for this soft job. ++ * @return Point on soft job timeline. ++ */ ++mali_timeline_point mali_soft_job_start(struct mali_soft_job *job, struct mali_timeline_fence *fence); ++ ++/** ++ * Use by user-space to signal that a soft job has completed. ++ * ++ * @note Only valid for soft jobs with type MALI_SOFT_JOB_TYPE_USER_SIGNALED. ++ * ++ * @note The soft job must be in state MALI_SOFT_JOB_STATE_STARTED for the signal to be successful. ++ * ++ * @note If the soft job was signaled successfully, or it received a time out, the soft job will be ++ * destroyed after this call and should no longer be used. ++ * ++ * @note This function will block until the soft job has been activated. ++ * ++ * @param system The soft job system the job was started in. ++ * @param job_id ID of soft job we are signaling. ++ * ++ * @return _MALI_OSK_ERR_ITEM_NOT_FOUND if the soft job ID was invalid, _MALI_OSK_ERR_TIMEOUT if the ++ * soft job was timed out or _MALI_OSK_ERR_OK if we successfully signaled the soft job. ++ */ ++_mali_osk_errcode_t mali_soft_job_system_signal_job(struct mali_soft_job_system *system, u32 job_id); ++ ++/** ++ * Used by the Timeline system to activate a soft job. ++ * ++ * @param job The soft job that is being activated. ++ */ ++void mali_soft_job_system_activate_job(struct mali_soft_job *job); ++ ++/** ++ * Used by the Timeline system to timeout a soft job. ++ * ++ * A soft job is timed out if it completes or is signaled later than MALI_TIMELINE_TIMEOUT_HZ after ++ * activation. ++ * ++ * @param job The soft job that is being timed out. ++ * @return A scheduling bitmask. ++ */ ++mali_scheduler_mask mali_soft_job_system_timeout_job(struct mali_soft_job *job); ++ ++/** ++ * Used to cleanup activated soft jobs in the soft job system on session abort. ++ * ++ * @param system The soft job system that is being aborted. ++ */ ++void mali_soft_job_system_abort(struct mali_soft_job_system *system); ++ ++#endif /* __MALI_SOFT_JOB_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.c +new file mode 100644 +index 0000000..bad217f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.c +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_spinlock_reentrant.h" ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++struct mali_spinlock_reentrant *mali_spinlock_reentrant_init(_mali_osk_lock_order_t lock_order) ++{ ++ struct mali_spinlock_reentrant *spinlock; ++ ++ spinlock = _mali_osk_calloc(1, sizeof(struct mali_spinlock_reentrant)); ++ if (NULL == spinlock) { ++ return NULL; ++ } ++ ++ spinlock->lock = _mali_osk_spinlock_irq_init(_MALI_OSK_LOCKFLAG_ORDERED, lock_order); ++ if (NULL == spinlock->lock) { ++ mali_spinlock_reentrant_term(spinlock); ++ return NULL; ++ } ++ ++ return spinlock; ++} ++ ++void mali_spinlock_reentrant_term(struct mali_spinlock_reentrant *spinlock) ++{ ++ MALI_DEBUG_ASSERT_POINTER(spinlock); ++ MALI_DEBUG_ASSERT(0 == spinlock->counter && 0 == spinlock->owner); ++ ++ if (NULL != spinlock->lock) { ++ _mali_osk_spinlock_irq_term(spinlock->lock); ++ } ++ ++ _mali_osk_free(spinlock); ++} ++ ++void mali_spinlock_reentrant_wait(struct mali_spinlock_reentrant *spinlock, u32 tid) ++{ ++ MALI_DEBUG_ASSERT_POINTER(spinlock); ++ MALI_DEBUG_ASSERT_POINTER(spinlock->lock); ++ MALI_DEBUG_ASSERT(0 != tid); ++ ++ MALI_DEBUG_PRINT(5, ("%s ^\n", __FUNCTION__)); ++ ++ if (tid != spinlock->owner) { ++ _mali_osk_spinlock_irq_lock(spinlock->lock); ++ MALI_DEBUG_ASSERT(0 == spinlock->owner && 0 == spinlock->counter); ++ spinlock->owner = tid; ++ } ++ ++ MALI_DEBUG_PRINT(5, ("%s v\n", __FUNCTION__)); ++ ++ ++spinlock->counter; ++} ++ ++void mali_spinlock_reentrant_signal(struct mali_spinlock_reentrant *spinlock, u32 tid) ++{ ++ MALI_DEBUG_ASSERT_POINTER(spinlock); ++ MALI_DEBUG_ASSERT_POINTER(spinlock->lock); ++ MALI_DEBUG_ASSERT(0 != tid && tid == spinlock->owner); ++ ++ --spinlock->counter; ++ if (0 == spinlock->counter) { ++ spinlock->owner = 0; ++ MALI_DEBUG_PRINT(5, ("%s release last\n", __FUNCTION__)); ++ _mali_osk_spinlock_irq_unlock(spinlock->lock); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.h +new file mode 100644 +index 0000000..16e99b7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_spinlock_reentrant.h +@@ -0,0 +1,70 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_SPINLOCK_REENTRANT_H__ ++#define __MALI_SPINLOCK_REENTRANT_H__ ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++/** ++ * Reentrant spinlock. ++ */ ++struct mali_spinlock_reentrant { ++ _mali_osk_spinlock_irq_t *lock; ++ u32 owner; ++ u32 counter; ++}; ++ ++/** ++ * Create a new reentrant spinlock. ++ * ++ * @param lock_order Lock order. ++ * @return New reentrant spinlock. ++ */ ++struct mali_spinlock_reentrant *mali_spinlock_reentrant_init(_mali_osk_lock_order_t lock_order); ++ ++/** ++ * Terminate reentrant spinlock and free any associated resources. ++ * ++ * @param spinlock Reentrant spinlock to terminate. ++ */ ++void mali_spinlock_reentrant_term(struct mali_spinlock_reentrant *spinlock); ++ ++/** ++ * Wait for reentrant spinlock to be signaled. ++ * ++ * @param spinlock Reentrant spinlock. ++ * @param tid Thread ID. ++ */ ++void mali_spinlock_reentrant_wait(struct mali_spinlock_reentrant *spinlock, u32 tid); ++ ++/** ++ * Signal reentrant spinlock. ++ * ++ * @param spinlock Reentrant spinlock. ++ * @param tid Thread ID. ++ */ ++void mali_spinlock_reentrant_signal(struct mali_spinlock_reentrant *spinlock, u32 tid); ++ ++/** ++ * Check if thread is holding reentrant spinlock. ++ * ++ * @param spinlock Reentrant spinlock. ++ * @param tid Thread ID. ++ * @return MALI_TRUE if thread is holding spinlock, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_spinlock_reentrant_is_held(struct mali_spinlock_reentrant *spinlock, u32 tid) ++{ ++ MALI_DEBUG_ASSERT_POINTER(spinlock->lock); ++ return (tid == spinlock->owner && 0 < spinlock->counter); ++} ++ ++#endif /* __MALI_SPINLOCK_REENTRANT_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.c +new file mode 100644 +index 0000000..955c748 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.c +@@ -0,0 +1,1374 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_timeline.h" ++#include "mali_kernel_common.h" ++#include "mali_osk_mali.h" ++#include "mali_scheduler.h" ++#include "mali_soft_job.h" ++#include "mali_timeline_fence_wait.h" ++#include "mali_timeline_sync_fence.h" ++ ++#define MALI_TIMELINE_SYSTEM_LOCKED(system) (mali_spinlock_reentrant_is_held((system)->spinlock, _mali_osk_get_tid())) ++ ++static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system, ++ struct mali_timeline_waiter *waiter); ++ ++#if defined(CONFIG_SYNC) ++/* Callback that is called when a sync fence a tracker is waiting on is signaled. */ ++static void mali_timeline_sync_fence_callback(struct sync_fence *sync_fence, struct sync_fence_waiter *sync_fence_waiter) ++{ ++ struct mali_timeline_system *system; ++ struct mali_timeline_waiter *waiter; ++ struct mali_timeline_tracker *tracker; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ u32 tid = _mali_osk_get_tid(); ++ mali_bool is_aborting = MALI_FALSE; ++ int fence_status = sync_fence->status; ++ ++ MALI_DEBUG_ASSERT_POINTER(sync_fence); ++ MALI_DEBUG_ASSERT_POINTER(sync_fence_waiter); ++ ++ tracker = _MALI_OSK_CONTAINER_OF(sync_fence_waiter, struct mali_timeline_tracker, sync_fence_waiter); ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ system = tracker->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ is_aborting = system->session->is_aborting; ++ if (!is_aborting && (0 > fence_status)) { ++ MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, fence_status)); ++ tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT; ++ } ++ ++ waiter = tracker->waiter_sync; ++ MALI_DEBUG_ASSERT_POINTER(waiter); ++ ++ tracker->sync_fence = NULL; ++ schedule_mask |= mali_timeline_system_release_waiter(system, waiter); ++ ++ /* If aborting, wake up sleepers that are waiting for sync fence callbacks to complete. */ ++ if (is_aborting) { ++ _mali_osk_wait_queue_wake_up(system->wait_queue); ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ sync_fence_put(sync_fence); ++ ++ if (!is_aborting) { ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_TRUE); ++ } ++} ++#endif /* defined(CONFIG_SYNC) */ ++ ++static mali_scheduler_mask mali_timeline_tracker_time_out(struct mali_timeline_tracker *tracker) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_SOFT == tracker->type); ++ ++ return mali_soft_job_system_timeout_job((struct mali_soft_job *) tracker->job); ++} ++ ++static void mali_timeline_timer_callback(void *data) ++{ ++ struct mali_timeline_system *system; ++ struct mali_timeline_tracker *tracker; ++ struct mali_timeline *timeline; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ u32 tid = _mali_osk_get_tid(); ++ ++ timeline = (struct mali_timeline *) data; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ system = timeline->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ if (!system->timer_enabled) { ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ return; ++ } ++ ++ tracker = timeline->tracker_tail; ++ timeline->timer_active = MALI_FALSE; ++ ++ if (NULL != tracker && MALI_TRUE == tracker->timer_active) { ++ /* This is likely the delayed work that has been schedule out before cancelled. */ ++ if (MALI_TIMELINE_TIMEOUT_HZ > (_mali_osk_time_tickcount() - tracker->os_tick_activate)) { ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ return; ++ } ++ ++ schedule_mask = mali_timeline_tracker_time_out(tracker); ++ tracker->timer_active = MALI_FALSE; ++ } else { ++ MALI_PRINT_ERROR(("Mali Timeline: Soft job timer callback without a waiting tracker.\n")); ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE); ++} ++ ++void mali_timeline_system_stop_timer(struct mali_timeline_system *system) ++{ ++ u32 i; ++ u32 tid = _mali_osk_get_tid(); ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ system->timer_enabled = MALI_FALSE; ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline = system->timelines[i]; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ if (NULL != timeline->delayed_work) { ++ _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work); ++ timeline->timer_active = MALI_FALSE; ++ } ++ } ++} ++ ++static void mali_timeline_destroy(struct mali_timeline *timeline) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ if (NULL != timeline) { ++ /* Assert that the timeline object has been properly cleaned up before destroying it. */ ++ MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next); ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_head); ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail); ++ MALI_DEBUG_ASSERT(NULL == timeline->waiter_head); ++ MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail); ++ MALI_DEBUG_ASSERT(NULL != timeline->system); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_MAX > timeline->id); ++ ++#if defined(CONFIG_SYNC) ++ if (NULL != timeline->sync_tl) { ++ sync_timeline_destroy(timeline->sync_tl); ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ if (NULL != timeline->delayed_work) { ++ _mali_osk_wq_delayed_cancel_work_sync(timeline->delayed_work); ++ _mali_osk_wq_delayed_delete_work_nonflush(timeline->delayed_work); ++ } ++ ++ _mali_osk_free(timeline); ++ } ++} ++ ++static struct mali_timeline *mali_timeline_create(struct mali_timeline_system *system, enum mali_timeline_id id) ++{ ++ struct mali_timeline *timeline; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT(id < MALI_TIMELINE_MAX); ++ ++ timeline = (struct mali_timeline *) _mali_osk_calloc(1, sizeof(struct mali_timeline)); ++ if (NULL == timeline) { ++ return NULL; ++ } ++ ++ /* Initially the timeline is empty. */ ++#if defined(MALI_TIMELINE_DEBUG_START_POINT) ++ /* Start the timeline a bit before wrapping when debugging. */ ++ timeline->point_next = UINT_MAX - MALI_TIMELINE_MAX_POINT_SPAN - 128; ++#else ++ timeline->point_next = 1; ++#endif ++ timeline->point_oldest = timeline->point_next; ++ ++ /* The tracker and waiter lists will initially be empty. */ ++ ++ timeline->system = system; ++ timeline->id = id; ++ ++ timeline->delayed_work = _mali_osk_wq_delayed_create_work(mali_timeline_timer_callback, timeline); ++ if (NULL == timeline->delayed_work) { ++ mali_timeline_destroy(timeline); ++ return NULL; ++ } ++ ++ timeline->timer_active = MALI_FALSE; ++ ++#if defined(CONFIG_SYNC) ++ { ++ char timeline_name[32]; ++ ++ switch (id) { ++ case MALI_TIMELINE_GP: ++ _mali_osk_snprintf(timeline_name, 32, "mali-%u-gp", _mali_osk_get_pid()); ++ break; ++ case MALI_TIMELINE_PP: ++ _mali_osk_snprintf(timeline_name, 32, "mali-%u-pp", _mali_osk_get_pid()); ++ break; ++ case MALI_TIMELINE_SOFT: ++ _mali_osk_snprintf(timeline_name, 32, "mali-%u-soft", _mali_osk_get_pid()); ++ break; ++ default: ++ MALI_PRINT_ERROR(("Mali Timeline: Invalid timeline id %d\n", id)); ++ mali_timeline_destroy(timeline); ++ return NULL; ++ } ++ ++ timeline->sync_tl = mali_sync_timeline_create(timeline_name); ++ if (NULL == timeline->sync_tl) { ++ mali_timeline_destroy(timeline); ++ return NULL; ++ } ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ return timeline; ++} ++ ++static void mali_timeline_insert_tracker(struct mali_timeline *timeline, struct mali_timeline_tracker *tracker) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ if (mali_timeline_is_full(timeline)) { ++ /* Don't add tracker if timeline is full. */ ++ tracker->point = MALI_TIMELINE_NO_POINT; ++ return; ++ } ++ ++ tracker->timeline = timeline; ++ tracker->point = timeline->point_next; ++ ++ /* Find next available point. */ ++ timeline->point_next++; ++ if (MALI_TIMELINE_NO_POINT == timeline->point_next) { ++ timeline->point_next++; ++ } ++ ++ MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline)); ++ ++ /* Add tracker as new head on timeline's tracker list. */ ++ if (NULL == timeline->tracker_head) { ++ /* Tracker list is empty. */ ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail); ++ ++ timeline->tracker_tail = tracker; ++ ++ MALI_DEBUG_ASSERT(NULL == tracker->timeline_next); ++ MALI_DEBUG_ASSERT(NULL == tracker->timeline_prev); ++ } else { ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next); ++ ++ tracker->timeline_prev = timeline->tracker_head; ++ timeline->tracker_head->timeline_next = tracker; ++ ++ MALI_DEBUG_ASSERT(NULL == tracker->timeline_next); ++ } ++ timeline->tracker_head = tracker; ++ ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_head->timeline_next); ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail->timeline_prev); ++} ++ ++/* Inserting the waiter object into the given timeline */ ++static void mali_timeline_insert_waiter(struct mali_timeline *timeline, struct mali_timeline_waiter *waiter_new) ++{ ++ struct mali_timeline_waiter *waiter_prev; ++ struct mali_timeline_waiter *waiter_next; ++ ++ /* Waiter time must be between timeline head and tail, and there must ++ * be less than MALI_TIMELINE_MAX_POINT_SPAN elements between */ ++ MALI_DEBUG_ASSERT(( waiter_new->point - timeline->point_oldest) < MALI_TIMELINE_MAX_POINT_SPAN); ++ MALI_DEBUG_ASSERT((-waiter_new->point + timeline->point_next) < MALI_TIMELINE_MAX_POINT_SPAN); ++ ++ /* Finding out where to put this waiter, in the linked waiter list of the given timeline **/ ++ waiter_prev = timeline->waiter_head; /* Insert new after waiter_prev */ ++ waiter_next = NULL; /* Insert new before waiter_next */ ++ ++ /* Iterating backwards from head (newest) to tail (oldest) until we ++ * find the correct spot to insert the new waiter */ ++ while (waiter_prev && mali_timeline_point_after(waiter_prev->point, waiter_new->point)) { ++ waiter_next = waiter_prev; ++ waiter_prev = waiter_prev->timeline_prev; ++ } ++ ++ if (NULL == waiter_prev && NULL == waiter_next) { ++ /* list is empty */ ++ timeline->waiter_head = waiter_new; ++ timeline->waiter_tail = waiter_new; ++ } else if (NULL == waiter_next) { ++ /* insert at head */ ++ waiter_new->timeline_prev = timeline->waiter_head; ++ timeline->waiter_head->timeline_next = waiter_new; ++ timeline->waiter_head = waiter_new; ++ } else if (NULL == waiter_prev) { ++ /* insert at tail */ ++ waiter_new->timeline_next = timeline->waiter_tail; ++ timeline->waiter_tail->timeline_prev = waiter_new; ++ timeline->waiter_tail = waiter_new; ++ } else { ++ /* insert between */ ++ waiter_new->timeline_next = waiter_next; ++ waiter_new->timeline_prev = waiter_prev; ++ waiter_next->timeline_prev = waiter_new; ++ waiter_prev->timeline_next = waiter_new; ++ } ++} ++ ++static void mali_timeline_update_delayed_work(struct mali_timeline *timeline) ++{ ++ struct mali_timeline_system *system; ++ struct mali_timeline_tracker *oldest_tracker; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SOFT == timeline->id); ++ ++ system = timeline->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ /* Timer is disabled, early out. */ ++ if (!system->timer_enabled) return; ++ ++ oldest_tracker = timeline->tracker_tail; ++ if (NULL != oldest_tracker && 0 == oldest_tracker->trigger_ref_count) { ++ if (MALI_FALSE == oldest_tracker->timer_active) { ++ if (MALI_TRUE == timeline->timer_active) { ++ _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work); ++ } ++ _mali_osk_wq_delayed_schedule_work(timeline->delayed_work, MALI_TIMELINE_TIMEOUT_HZ); ++ oldest_tracker->timer_active = MALI_TRUE; ++ timeline->timer_active = MALI_TRUE; ++ } ++ } else if (MALI_TRUE == timeline->timer_active) { ++ _mali_osk_wq_delayed_cancel_work_async(timeline->delayed_work); ++ timeline->timer_active = MALI_FALSE; ++ } ++} ++ ++static mali_scheduler_mask mali_timeline_update_oldest_point(struct mali_timeline *timeline) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ MALI_DEBUG_CODE({ ++ struct mali_timeline_system *system = timeline->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ }); ++ ++ if (NULL != timeline->tracker_tail) { ++ /* Set oldest point to oldest tracker's point */ ++ timeline->point_oldest = timeline->tracker_tail->point; ++ } else { ++ /* No trackers, mark point list as empty */ ++ timeline->point_oldest = timeline->point_next; ++ } ++ ++ /* Release all waiters no longer on the timeline's point list. ++ * Releasing a waiter can trigger this function to be called again, so ++ * we do not store any pointers on stack. */ ++ while (NULL != timeline->waiter_tail) { ++ u32 waiter_time_relative; ++ u32 time_head_relative; ++ struct mali_timeline_waiter *waiter = timeline->waiter_tail; ++ ++ time_head_relative = timeline->point_next - timeline->point_oldest; ++ waiter_time_relative = waiter->point - timeline->point_oldest; ++ ++ if (waiter_time_relative < time_head_relative) { ++ /* This and all following waiters are on the point list, so we are done. */ ++ break; ++ } ++ ++ /* Remove waiter from timeline's waiter list. */ ++ if (NULL != waiter->timeline_next) { ++ waiter->timeline_next->timeline_prev = NULL; ++ } else { ++ /* This was the last waiter */ ++ timeline->waiter_head = NULL; ++ } ++ timeline->waiter_tail = waiter->timeline_next; ++ ++ /* Release waiter. This could activate a tracker, if this was ++ * the last waiter for the tracker. */ ++ schedule_mask |= mali_timeline_system_release_waiter(timeline->system, waiter); ++ } ++ ++ return schedule_mask; ++} ++ ++void mali_timeline_tracker_init(struct mali_timeline_tracker *tracker, ++ mali_timeline_tracker_type type, ++ struct mali_timeline_fence *fence, ++ void *job) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT_POINTER(job); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > type); ++ ++ /* Zero out all tracker members. */ ++ _mali_osk_memset(tracker, 0, sizeof(*tracker)); ++ ++ tracker->type = type; ++ tracker->job = job; ++ tracker->trigger_ref_count = 1; /* Prevents any callback from trigging while adding it */ ++ tracker->os_tick_create = _mali_osk_time_tickcount(); ++ MALI_DEBUG_CODE(tracker->magic = MALI_TIMELINE_TRACKER_MAGIC); ++ ++ tracker->activation_error = MALI_TIMELINE_ACTIVATION_ERROR_NONE; ++ ++ /* Copy fence. */ ++ if (NULL != fence) { ++ _mali_osk_memcpy(&tracker->fence, fence, sizeof(struct mali_timeline_fence)); ++ } ++} ++ ++mali_scheduler_mask mali_timeline_tracker_release(struct mali_timeline_tracker *tracker) ++{ ++ struct mali_timeline *timeline; ++ struct mali_timeline_system *system; ++ struct mali_timeline_tracker *tracker_next, *tracker_prev; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ u32 tid = _mali_osk_get_tid(); ++ ++ /* Upon entry a group lock will be held, but not a scheduler lock. */ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic); ++ ++ /* Tracker should have been triggered */ ++ MALI_DEBUG_ASSERT(0 == tracker->trigger_ref_count); ++ ++ /* All waiters should have been released at this point */ ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_head); ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail); ++ ++ MALI_DEBUG_PRINT(3, ("Mali Timeline: releasing tracker for job 0x%08X\n", tracker->job)); ++ ++ timeline = tracker->timeline; ++ if (NULL == timeline) { ++ /* Tracker was not on a timeline, there is nothing to release. */ ++ return MALI_SCHEDULER_MASK_EMPTY; ++ } ++ ++ system = timeline->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ /* Tracker should still be on timeline */ ++ MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline)); ++ MALI_DEBUG_ASSERT( mali_timeline_is_point_on(timeline, tracker->point)); ++ ++ /* Tracker is no longer valid. */ ++ MALI_DEBUG_CODE(tracker->magic = 0); ++ ++ tracker_next = tracker->timeline_next; ++ tracker_prev = tracker->timeline_prev; ++ tracker->timeline_next = NULL; ++ tracker->timeline_prev = NULL; ++ ++ /* Removing tracker from timeline's tracker list */ ++ if (NULL == tracker_next) { ++ /* This tracker was the head */ ++ timeline->tracker_head = tracker_prev; ++ } else { ++ tracker_next->timeline_prev = tracker_prev; ++ } ++ ++ if (NULL == tracker_prev) { ++ /* This tracker was the tail */ ++ timeline->tracker_tail = tracker_next; ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ /* Update the timeline's oldest time and release any waiters */ ++ schedule_mask |= mali_timeline_update_oldest_point(timeline); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ } else { ++ tracker_prev->timeline_next = tracker_next; ++ } ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ /* Update delayed work only when it is the soft job timeline */ ++ if (MALI_TIMELINE_SOFT == tracker->timeline->id) { ++ mali_timeline_update_delayed_work(tracker->timeline); ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ return schedule_mask; ++} ++ ++void mali_timeline_system_release_waiter_list(struct mali_timeline_system *system, ++ struct mali_timeline_waiter *tail, ++ struct mali_timeline_waiter *head) ++{ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(head); ++ MALI_DEBUG_ASSERT_POINTER(tail); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ head->tracker_next = system->waiter_empty_list; ++ system->waiter_empty_list = tail; ++} ++ ++static mali_scheduler_mask mali_timeline_tracker_activate(struct mali_timeline_tracker *tracker) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ struct mali_timeline_system *system; ++ struct mali_timeline *timeline; ++ u32 tid = _mali_osk_get_tid(); ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic); ++ ++ system = tracker->system; ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ tracker->os_tick_activate = _mali_osk_time_tickcount(); ++ ++ if (NULL != tracker->waiter_head) { ++ mali_timeline_system_release_waiter_list(system, tracker->waiter_tail, tracker->waiter_head); ++ tracker->waiter_head = NULL; ++ tracker->waiter_tail = NULL; ++ } ++ ++ switch (tracker->type) { ++ case MALI_TIMELINE_TRACKER_GP: ++ schedule_mask = mali_gp_scheduler_activate_job((struct mali_gp_job *) tracker->job); ++ break; ++ case MALI_TIMELINE_TRACKER_PP: ++ schedule_mask = mali_pp_scheduler_activate_job((struct mali_pp_job *) tracker->job); ++ break; ++ case MALI_TIMELINE_TRACKER_SOFT: ++ timeline = tracker->timeline; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ mali_soft_job_system_activate_job((struct mali_soft_job *) tracker->job); ++ ++ /* Start a soft timer to make sure the soft job be released in a limited time */ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ mali_timeline_update_delayed_work(timeline); ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ break; ++ case MALI_TIMELINE_TRACKER_WAIT: ++ mali_timeline_fence_wait_activate((struct mali_timeline_fence_wait_tracker *) tracker->job); ++ break; ++ case MALI_TIMELINE_TRACKER_SYNC: ++#if defined(CONFIG_SYNC) ++ mali_timeline_sync_fence_activate((struct mali_timeline_sync_fence_tracker *) tracker->job); ++#else ++ MALI_PRINT_ERROR(("Mali Timeline: sync tracker not supported\n", tracker->type)); ++#endif /* defined(CONFIG_SYNC) */ ++ break; ++ default: ++ MALI_PRINT_ERROR(("Mali Timeline - Illegal tracker type: %d\n", tracker->type)); ++ break; ++ } ++ ++ return schedule_mask; ++} ++ ++void mali_timeline_system_tracker_get(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker) ++{ ++ u32 tid = _mali_osk_get_tid(); ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count); ++ tracker->trigger_ref_count++; ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++} ++ ++mali_scheduler_mask mali_timeline_system_tracker_put(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker, mali_timeline_activation_error activation_error) ++{ ++ u32 tid = _mali_osk_get_tid(); ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count); ++ tracker->trigger_ref_count--; ++ ++ tracker->activation_error |= activation_error; ++ ++ if (0 == tracker->trigger_ref_count) { ++ schedule_mask |= mali_timeline_tracker_activate(tracker); ++ tracker = NULL; ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ return schedule_mask; ++} ++ ++void mali_timeline_fence_copy_uk_fence(struct mali_timeline_fence *fence, _mali_uk_fence_t *uk_fence) ++{ ++ u32 i; ++ ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ MALI_DEBUG_ASSERT_POINTER(uk_fence); ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ fence->points[i] = uk_fence->points[i]; ++ } ++ ++ fence->sync_fd = uk_fence->sync_fd; ++} ++ ++struct mali_timeline_system *mali_timeline_system_create(struct mali_session_data *session) ++{ ++ u32 i; ++ struct mali_timeline_system *system; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: creating timeline system\n")); ++ ++ system = (struct mali_timeline_system *) _mali_osk_calloc(1, sizeof(struct mali_timeline_system)); ++ if (NULL == system) { ++ return NULL; ++ } ++ ++ system->spinlock = mali_spinlock_reentrant_init(_MALI_OSK_LOCK_ORDER_TIMELINE_SYSTEM); ++ if (NULL == system->spinlock) { ++ mali_timeline_system_destroy(system); ++ return NULL; ++ } ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ system->timelines[i] = mali_timeline_create(system, (enum mali_timeline_id)i); ++ if (NULL == system->timelines[i]) { ++ mali_timeline_system_destroy(system); ++ return NULL; ++ } ++ } ++ ++#if defined(CONFIG_SYNC) ++ system->signaled_sync_tl = mali_sync_timeline_create("mali-always-signaled"); ++ if (NULL == system->signaled_sync_tl) { ++ mali_timeline_system_destroy(system); ++ return NULL; ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ system->waiter_empty_list = NULL; ++ system->session = session; ++ system->timer_enabled = MALI_TRUE; ++ ++ system->wait_queue = _mali_osk_wait_queue_init(); ++ if (NULL == system->wait_queue) { ++ mali_timeline_system_destroy(system); ++ return NULL; ++ } ++ ++ return system; ++} ++ ++#if defined(CONFIG_SYNC) ++ ++/** ++ * Check if there are any trackers left on timeline. ++ * ++ * Used as a wait queue conditional. ++ * ++ * @param data Timeline. ++ * @return MALI_TRUE if there are no trackers on timeline, MALI_FALSE if not. ++ */ ++static mali_bool mali_timeline_has_no_trackers(void *data) ++{ ++ struct mali_timeline *timeline = (struct mali_timeline *) data; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ return mali_timeline_is_empty(timeline); ++} ++ ++/** ++ * Cancel sync fence waiters waited upon by trackers on all timelines. ++ * ++ * Will return after all timelines have no trackers left. ++ * ++ * @param system Timeline system. ++ */ ++static void mali_timeline_cancel_sync_fence_waiters(struct mali_timeline_system *system) ++{ ++ u32 i; ++ u32 tid = _mali_osk_get_tid(); ++ struct mali_timeline_tracker *tracker, *tracker_next; ++ _MALI_OSK_LIST_HEAD_STATIC_INIT(tracker_list); ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ MALI_DEBUG_ASSERT(system->session->is_aborting); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ /* Cancel sync fence waiters. */ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline = system->timelines[i]; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ tracker_next = timeline->tracker_tail; ++ while (NULL != tracker_next) { ++ tracker = tracker_next; ++ tracker_next = tracker->timeline_next; ++ ++ if (NULL == tracker->sync_fence) continue; ++ ++ MALI_DEBUG_PRINT(3, ("Mali Timeline: Cancelling sync fence wait for tracker 0x%08X.\n", tracker)); ++ ++ /* Cancel sync fence waiter. */ ++ if (0 == sync_fence_cancel_async(tracker->sync_fence, &tracker->sync_fence_waiter)) { ++ /* Callback was not called, move tracker to local list. */ ++ _mali_osk_list_add(&tracker->sync_fence_cancel_list, &tracker_list); ++ } ++ } ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ /* Manually call sync fence callback in order to release waiter and trigger activation of tracker. */ ++ _MALI_OSK_LIST_FOREACHENTRY(tracker, tracker_next, &tracker_list, struct mali_timeline_tracker, sync_fence_cancel_list) { ++ mali_timeline_sync_fence_callback(tracker->sync_fence, &tracker->sync_fence_waiter); ++ } ++ ++ /* Sleep until all sync fence callbacks are done and all timelines are empty. */ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline = system->timelines[i]; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ _mali_osk_wait_queue_wait_event(system->wait_queue, mali_timeline_has_no_trackers, (void *) timeline); ++ } ++} ++ ++#endif /* defined(CONFIG_SYNC) */ ++ ++void mali_timeline_system_abort(struct mali_timeline_system *system) ++{ ++ MALI_DEBUG_CODE(u32 tid = _mali_osk_get_tid();); ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ MALI_DEBUG_ASSERT(system->session->is_aborting); ++ ++ MALI_DEBUG_PRINT(3, ("Mali Timeline: Aborting timeline system for session 0x%08X.\n", system->session)); ++ ++#if defined(CONFIG_SYNC) ++ mali_timeline_cancel_sync_fence_waiters(system); ++#endif /* defined(CONFIG_SYNC) */ ++ ++ /* Should not be any waiters or trackers left at this point. */ ++ MALI_DEBUG_CODE( { ++ u32 i; ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) ++ { ++ struct mali_timeline *timeline = system->timelines[i]; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT(timeline->point_oldest == timeline->point_next); ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_head); ++ MALI_DEBUG_ASSERT(NULL == timeline->tracker_tail); ++ MALI_DEBUG_ASSERT(NULL == timeline->waiter_head); ++ MALI_DEBUG_ASSERT(NULL == timeline->waiter_tail); ++ } ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ }); ++} ++ ++void mali_timeline_system_destroy(struct mali_timeline_system *system) ++{ ++ u32 i; ++ struct mali_timeline_waiter *waiter, *next; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: destroying timeline system\n")); ++ ++ if (NULL != system) { ++ /* There should be no waiters left on this queue. */ ++ if (NULL != system->wait_queue) { ++ _mali_osk_wait_queue_term(system->wait_queue); ++ system->wait_queue = NULL; ++ } ++ ++ /* Free all waiters in empty list */ ++ waiter = system->waiter_empty_list; ++ while (NULL != waiter) { ++ next = waiter->tracker_next; ++ _mali_osk_free(waiter); ++ waiter = next; ++ } ++ ++#if defined(CONFIG_SYNC) ++ if (NULL != system->signaled_sync_tl) { ++ sync_timeline_destroy(system->signaled_sync_tl); ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ if (NULL != system->timelines[i]) { ++ mali_timeline_destroy(system->timelines[i]); ++ } ++ } ++ if (NULL != system->spinlock) { ++ mali_spinlock_reentrant_term(system->spinlock); ++ } ++ ++ _mali_osk_free(system); ++ } ++} ++ ++/** ++ * Find how many waiters are needed for a given fence. ++ * ++ * @param fence The fence to check. ++ * @return Number of waiters needed for fence. ++ */ ++static u32 mali_timeline_fence_num_waiters(struct mali_timeline_fence *fence) ++{ ++ u32 i, num_waiters = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ if (MALI_TIMELINE_NO_POINT != fence->points[i]) { ++ ++num_waiters; ++ } ++ } ++ ++#if defined(CONFIG_SYNC) ++ if (-1 != fence->sync_fd) ++num_waiters; ++#endif /* defined(CONFIG_SYNC) */ ++ ++ return num_waiters; ++} ++ ++static struct mali_timeline_waiter *mali_timeline_system_get_zeroed_waiter(struct mali_timeline_system *system) ++{ ++ struct mali_timeline_waiter *waiter; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ waiter = system->waiter_empty_list; ++ if (NULL != waiter) { ++ /* Remove waiter from empty list and zero it */ ++ system->waiter_empty_list = waiter->tracker_next; ++ _mali_osk_memset(waiter, 0, sizeof(*waiter)); ++ } ++ ++ /* Return NULL if list was empty. */ ++ return waiter; ++} ++ ++static void mali_timeline_system_allocate_waiters(struct mali_timeline_system *system, ++ struct mali_timeline_waiter **tail, ++ struct mali_timeline_waiter **head, ++ int max_num_waiters) ++{ ++ u32 i, tid = _mali_osk_get_tid(); ++ mali_bool do_alloc; ++ struct mali_timeline_waiter *waiter; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(tail); ++ MALI_DEBUG_ASSERT_POINTER(head); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ *head = *tail = NULL; ++ do_alloc = MALI_FALSE; ++ i = 0; ++ while (i < max_num_waiters) { ++ if (MALI_FALSE == do_alloc) { ++ waiter = mali_timeline_system_get_zeroed_waiter(system); ++ if (NULL == waiter) { ++ do_alloc = MALI_TRUE; ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ continue; ++ } ++ } else { ++ waiter = _mali_osk_calloc(1, sizeof(struct mali_timeline_waiter)); ++ if (NULL == waiter) break; ++ } ++ ++i; ++ if (NULL == *tail) { ++ *tail = waiter; ++ *head = waiter; ++ } else { ++ (*head)->tracker_next = waiter; ++ *head = waiter; ++ } ++ } ++ if (MALI_TRUE == do_alloc) { ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ } ++} ++ ++/** ++ * Create waiters for the given tracker. The tracker is activated when all waiters are release. ++ * ++ * @note Tracker can potentially be activated before this function returns. ++ * ++ * @param system Timeline system. ++ * @param tracker Tracker we will create waiters for. ++ * @param waiter_tail List of pre-allocated waiters. ++ * @param waiter_head List of pre-allocated waiters. ++ */ ++static void mali_timeline_system_create_waiters_and_unlock(struct mali_timeline_system *system, ++ struct mali_timeline_tracker *tracker, ++ struct mali_timeline_waiter *waiter_tail, ++ struct mali_timeline_waiter *waiter_head) ++{ ++ int i; ++ u32 tid = _mali_osk_get_tid(); ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++#if defined(CONFIG_SYNC) ++ struct sync_fence *sync_fence = NULL; ++#endif /* defined(CONFIG_SYNC) */ ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_head); ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail); ++ MALI_DEBUG_ASSERT(NULL != tracker->job); ++ ++ /* Creating waiter object for all the timelines the fence is put on. Inserting this waiter ++ * into the timelines sorted list of waiters */ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ mali_timeline_point point; ++ struct mali_timeline *timeline; ++ struct mali_timeline_waiter *waiter; ++ ++ /* Get point on current timeline from tracker's fence. */ ++ point = tracker->fence.points[i]; ++ ++ if (likely(MALI_TIMELINE_NO_POINT == point)) { ++ /* Fence contains no point on this timeline so we don't need a waiter. */ ++ continue; ++ } ++ ++ timeline = system->timelines[i]; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ if (unlikely(!mali_timeline_is_point_valid(timeline, point))) { ++ MALI_PRINT_ERROR(("Mali Timeline: point %d is not valid (oldest=%d, next=%d)\n", ++ point, timeline->point_oldest, timeline->point_next)); ++ continue; ++ } ++ ++ if (likely(mali_timeline_is_point_released(timeline, point))) { ++ /* Tracker representing the point has been released so we don't need a ++ * waiter. */ ++ continue; ++ } ++ ++ /* The point is on timeline. */ ++ MALI_DEBUG_ASSERT(mali_timeline_is_point_on(timeline, point)); ++ ++ /* Get a new zeroed waiter object. */ ++ if (likely(NULL != waiter_tail)) { ++ waiter = waiter_tail; ++ waiter_tail = waiter_tail->tracker_next; ++ } else { ++ MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n")); ++ continue; ++ } ++ ++ /* Yanking the trigger ref count of the tracker. */ ++ tracker->trigger_ref_count++; ++ ++ waiter->point = point; ++ waiter->tracker = tracker; ++ ++ /* Insert waiter on tracker's singly-linked waiter list. */ ++ if (NULL == tracker->waiter_head) { ++ /* list is empty */ ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail); ++ tracker->waiter_tail = waiter; ++ } else { ++ tracker->waiter_head->tracker_next = waiter; ++ } ++ tracker->waiter_head = waiter; ++ ++ /* Add waiter to timeline. */ ++ mali_timeline_insert_waiter(timeline, waiter); ++ } ++#if defined(CONFIG_SYNC) ++ if (-1 != tracker->fence.sync_fd) { ++ int ret; ++ struct mali_timeline_waiter *waiter; ++ ++ sync_fence = sync_fence_fdget(tracker->fence.sync_fd); ++ if (unlikely(NULL == sync_fence)) { ++ MALI_PRINT_ERROR(("Mali Timeline: failed to get sync fence from fd %d\n", tracker->fence.sync_fd)); ++ goto exit; ++ } ++ ++ /* Check if we have a zeroed waiter object available. */ ++ if (unlikely(NULL == waiter_tail)) { ++ MALI_PRINT_ERROR(("Mali Timeline: failed to allocate memory for waiter\n")); ++ goto exit; ++ } ++ ++ /* Start asynchronous wait that will release waiter when the fence is signaled. */ ++ sync_fence_waiter_init(&tracker->sync_fence_waiter, mali_timeline_sync_fence_callback); ++ ret = sync_fence_wait_async(sync_fence, &tracker->sync_fence_waiter); ++ if (1 == ret) { ++ /* Fence already signaled, no waiter needed. */ ++ goto exit; ++ } else if (0 != ret) { ++ MALI_PRINT_ERROR(("Mali Timeline: sync fence fd %d signaled with error %d\n", tracker->fence.sync_fd, ret)); ++ tracker->activation_error |= MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT; ++ goto exit; ++ } ++ ++ /* Grab new zeroed waiter object. */ ++ waiter = waiter_tail; ++ waiter_tail = waiter_tail->tracker_next; ++ ++ /* Increase the trigger ref count of the tracker. */ ++ tracker->trigger_ref_count++; ++ ++ waiter->point = MALI_TIMELINE_NO_POINT; ++ waiter->tracker = tracker; ++ ++ /* Insert waiter on tracker's singly-linked waiter list. */ ++ if (NULL == tracker->waiter_head) { ++ /* list is empty */ ++ MALI_DEBUG_ASSERT(NULL == tracker->waiter_tail); ++ tracker->waiter_tail = waiter; ++ } else { ++ tracker->waiter_head->tracker_next = waiter; ++ } ++ tracker->waiter_head = waiter; ++ ++ /* Also store waiter in separate field for easy access by sync callback. */ ++ tracker->waiter_sync = waiter; ++ ++ /* Store the sync fence in tracker so we can retrieve in abort session, if needed. */ ++ tracker->sync_fence = sync_fence; ++ ++ sync_fence = NULL; ++ } ++exit: ++#endif /* defined(CONFIG_SYNC) */ ++ ++ if (NULL != waiter_tail) { ++ mali_timeline_system_release_waiter_list(system, waiter_tail, waiter_head); ++ } ++ ++ /* Release the initial trigger ref count. */ ++ tracker->trigger_ref_count--; ++ ++ /* If there were no waiters added to this tracker we activate immediately. */ ++ if (0 == tracker->trigger_ref_count) { ++ schedule_mask |= mali_timeline_tracker_activate(tracker); ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++#if defined(CONFIG_SYNC) ++ if (NULL != sync_fence) { ++ sync_fence_put(sync_fence); ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ mali_scheduler_schedule_from_mask(schedule_mask, MALI_FALSE); ++} ++ ++mali_timeline_point mali_timeline_system_add_tracker(struct mali_timeline_system *system, ++ struct mali_timeline_tracker *tracker, ++ enum mali_timeline_id timeline_id) ++{ ++ int num_waiters = 0; ++ struct mali_timeline_waiter *waiter_tail, *waiter_head; ++ u32 tid = _mali_osk_get_tid(); ++ mali_timeline_point point = MALI_TIMELINE_NO_POINT; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(system->session); ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ MALI_DEBUG_ASSERT(MALI_FALSE == system->session->is_aborting); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAX > tracker->type); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_TRACKER_MAGIC == tracker->magic); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: adding tracker for job %p, timeline: %d\n", tracker->job, timeline_id)); ++ ++ MALI_DEBUG_ASSERT(0 < tracker->trigger_ref_count); ++ tracker->system = system; ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ num_waiters = mali_timeline_fence_num_waiters(&tracker->fence); ++ ++ /* Allocate waiters. */ ++ mali_timeline_system_allocate_waiters(system, &waiter_tail, &waiter_head, num_waiters); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ /* Add tracker to timeline. This will allocate a point for the tracker on the timeline. If ++ * timeline ID is MALI_TIMELINE_NONE the tracker will NOT be added to a timeline and the ++ * point will be MALI_TIMELINE_NO_POINT. ++ * ++ * NOTE: the tracker can fail to be added if the timeline is full. If this happens, the ++ * point will be MALI_TIMELINE_NO_POINT. */ ++ MALI_DEBUG_ASSERT(timeline_id < MALI_TIMELINE_MAX || timeline_id == MALI_TIMELINE_NONE); ++ if (likely(timeline_id < MALI_TIMELINE_MAX)) { ++ struct mali_timeline *timeline = system->timelines[timeline_id]; ++ mali_timeline_insert_tracker(timeline, tracker); ++ MALI_DEBUG_ASSERT(!mali_timeline_is_empty(timeline)); ++ } ++ ++ point = tracker->point; ++ ++ /* Create waiters for tracker based on supplied fence. Each waiter will increase the ++ * trigger ref count. */ ++ mali_timeline_system_create_waiters_and_unlock(system, tracker, waiter_tail, waiter_head); ++ tracker = NULL; ++ ++ /* At this point the tracker object might have been freed so we should no longer ++ * access it. */ ++ ++ ++ /* The tracker will always be activated after calling add_tracker, even if NO_POINT is ++ * returned. */ ++ return point; ++} ++ ++static mali_scheduler_mask mali_timeline_system_release_waiter(struct mali_timeline_system *system, ++ struct mali_timeline_waiter *waiter) ++{ ++ struct mali_timeline_tracker *tracker; ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(waiter); ++ ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_SYSTEM_LOCKED(system)); ++ ++ tracker = waiter->tracker; ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ /* At this point the waiter has been removed from the timeline's waiter list, but it is ++ * still on the tracker's waiter list. All of the tracker's waiters will be released when ++ * the tracker is activated. */ ++ ++ waiter->point = MALI_TIMELINE_NO_POINT; ++ waiter->tracker = NULL; ++ ++ tracker->trigger_ref_count--; ++ if (0 == tracker->trigger_ref_count) { ++ /* This was the last waiter; activate tracker */ ++ schedule_mask |= mali_timeline_tracker_activate(tracker); ++ tracker = NULL; ++ } ++ ++ return schedule_mask; ++} ++ ++mali_timeline_point mali_timeline_system_get_latest_point(struct mali_timeline_system *system, ++ enum mali_timeline_id timeline_id) ++{ ++ mali_timeline_point point; ++ struct mali_timeline *timeline; ++ u32 tid = _mali_osk_get_tid(); ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ if (MALI_TIMELINE_MAX <= timeline_id) { ++ return MALI_TIMELINE_NO_POINT; ++ } ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ timeline = system->timelines[timeline_id]; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ point = MALI_TIMELINE_NO_POINT; ++ if (timeline->point_oldest != timeline->point_next) { ++ point = timeline->point_next - 1; ++ if (MALI_TIMELINE_NO_POINT == point) point--; ++ } ++ ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++ return point; ++} ++ ++#if defined(MALI_TIMELINE_DEBUG_FUNCTIONS) ++ ++static mali_bool is_waiting_on_timeline(struct mali_timeline_tracker *tracker, enum mali_timeline_id id) ++{ ++ struct mali_timeline *timeline; ++ struct mali_timeline_system *system; ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker->timeline); ++ timeline = tracker->timeline; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline->system); ++ system = timeline->system; ++ ++ if (MALI_TIMELINE_MAX > id) { ++ return mali_timeline_is_point_on(system->timelines[id], tracker->fence.points[id]); ++ } else { ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NONE == id); ++ return MALI_FALSE; ++ } ++} ++ ++static const char *timeline_id_to_string(enum mali_timeline_id id) ++{ ++ switch (id) { ++ case MALI_TIMELINE_GP: ++ return " GP"; ++ case MALI_TIMELINE_PP: ++ return " PP"; ++ case MALI_TIMELINE_SOFT: ++ return "SOFT"; ++ default: ++ return "NONE"; ++ } ++} ++ ++static const char *timeline_tracker_type_to_string(enum mali_timeline_tracker_type type) ++{ ++ switch (type) { ++ case MALI_TIMELINE_TRACKER_GP: ++ return " GP"; ++ case MALI_TIMELINE_TRACKER_PP: ++ return " PP"; ++ case MALI_TIMELINE_TRACKER_SOFT: ++ return "SOFT"; ++ case MALI_TIMELINE_TRACKER_WAIT: ++ return "WAIT"; ++ case MALI_TIMELINE_TRACKER_SYNC: ++ return "SYNC"; ++ default: ++ return "INVALID"; ++ } ++} ++ ++mali_timeline_tracker_state mali_timeline_debug_get_tracker_state(struct mali_timeline_tracker *tracker) ++{ ++ struct mali_timeline *timeline = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ timeline = tracker->timeline; ++ ++ if (0 != tracker->trigger_ref_count) { ++ return MALI_TIMELINE_TS_WAITING; ++ } ++ ++ if (timeline && (timeline->tracker_tail == tracker || NULL != tracker->timeline_prev)) { ++ return MALI_TIMELINE_TS_ACTIVE; ++ } ++ ++ if (timeline && (MALI_TIMELINE_NO_POINT == tracker->point)) { ++ return MALI_TIMELINE_TS_INIT; ++ } ++ ++ return MALI_TIMELINE_TS_FINISH; ++} ++ ++void mali_timeline_debug_print_tracker(struct mali_timeline_tracker *tracker) ++{ ++ const char *tracker_state = "IWAF"; ++ ++ MALI_DEBUG_ASSERT_POINTER(tracker); ++ ++ if (0 != tracker->trigger_ref_count) { ++ MALI_PRINTF(("TL: %s %u %c - ref_wait:%u [%s%u,%s%u,%s%u,%d] (0x%08X)\n", ++ timeline_tracker_type_to_string(tracker->type), tracker->point, ++ *(tracker_state + mali_timeline_debug_get_tracker_state(tracker)), ++ tracker->trigger_ref_count, ++ is_waiting_on_timeline(tracker, MALI_TIMELINE_GP) ? "W" : " ", tracker->fence.points[0], ++ is_waiting_on_timeline(tracker, MALI_TIMELINE_PP) ? "W" : " ", tracker->fence.points[1], ++ is_waiting_on_timeline(tracker, MALI_TIMELINE_SOFT) ? "W" : " ", tracker->fence.points[2], ++ tracker->fence.sync_fd, tracker->job)); ++ } else { ++ MALI_PRINTF(("TL: %s %u %c (0x%08X)\n", ++ timeline_tracker_type_to_string(tracker->type), tracker->point, ++ *(tracker_state + mali_timeline_debug_get_tracker_state(tracker)), ++ tracker->job)); ++ } ++} ++ ++void mali_timeline_debug_print_timeline(struct mali_timeline *timeline) ++{ ++ struct mali_timeline_tracker *tracker = NULL; ++ int i_max = 30; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ tracker = timeline->tracker_tail; ++ while (NULL != tracker && 0 < --i_max) { ++ mali_timeline_debug_print_tracker(tracker); ++ tracker = tracker->timeline_next; ++ } ++ ++ if (0 == i_max) { ++ MALI_PRINTF(("TL: Too many trackers in list to print\n")); ++ } ++} ++ ++void mali_timeline_debug_print_system(struct mali_timeline_system *system) ++{ ++ int i; ++ int num_printed = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ ++ /* Print all timelines */ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline = system->timelines[i]; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ if (NULL == timeline->tracker_head) continue; ++ ++ MALI_PRINTF(("TL: Timeline %s:\n", ++ timeline_id_to_string((enum mali_timeline_id)i))); ++ mali_timeline_debug_print_timeline(timeline); ++ num_printed++; ++ } ++ ++ if (0 == num_printed) { ++ MALI_PRINTF(("TL: All timelines empty\n")); ++ } ++} ++ ++#endif /* defined(MALI_TIMELINE_DEBUG_FUNCTIONS) */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.h +new file mode 100644 +index 0000000..e014637 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline.h +@@ -0,0 +1,494 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_TIMELINE_H__ ++#define __MALI_TIMELINE_H__ ++ ++#include "mali_osk.h" ++#include "mali_ukk.h" ++#include "mali_session.h" ++#include "mali_kernel_common.h" ++#include "mali_spinlock_reentrant.h" ++#include "mali_sync.h" ++#include "mali_scheduler_types.h" ++ ++/** ++ * Soft job timeout. ++ * ++ * Soft jobs have to be signaled as complete after activation. Normally this is done by user space, ++ * but in order to guarantee that every soft job is completed, we also have a timer. ++ */ ++#define MALI_TIMELINE_TIMEOUT_HZ ((u32) (HZ * 3 / 2)) /* 1500 ms. */ ++ ++/** ++ * Timeline type. ++ */ ++typedef enum mali_timeline_id { ++ MALI_TIMELINE_GP = MALI_UK_TIMELINE_GP, /**< GP job timeline. */ ++ MALI_TIMELINE_PP = MALI_UK_TIMELINE_PP, /**< PP job timeline. */ ++ MALI_TIMELINE_SOFT = MALI_UK_TIMELINE_SOFT, /**< Soft job timeline. */ ++ MALI_TIMELINE_MAX = MALI_UK_TIMELINE_MAX ++} mali_timeline_id; ++ ++/** ++ * Used by trackers that should not be added to a timeline (@ref mali_timeline_system_add_tracker). ++ */ ++#define MALI_TIMELINE_NONE MALI_TIMELINE_MAX ++ ++/** ++ * Tracker type. ++ */ ++typedef enum mali_timeline_tracker_type { ++ MALI_TIMELINE_TRACKER_GP = 0, /**< Tracker used by GP jobs. */ ++ MALI_TIMELINE_TRACKER_PP = 1, /**< Tracker used by PP jobs. */ ++ MALI_TIMELINE_TRACKER_SOFT = 2, /**< Tracker used by soft jobs. */ ++ MALI_TIMELINE_TRACKER_WAIT = 3, /**< Tracker used for fence wait. */ ++ MALI_TIMELINE_TRACKER_SYNC = 4, /**< Tracker used for sync fence. */ ++ MALI_TIMELINE_TRACKER_MAX = 5, ++} mali_timeline_tracker_type; ++ ++/** ++ * Tracker activation error. ++ */ ++typedef u32 mali_timeline_activation_error; ++#define MALI_TIMELINE_ACTIVATION_ERROR_NONE 0 ++#define MALI_TIMELINE_ACTIVATION_ERROR_SYNC_BIT (1<<1) ++#define MALI_TIMELINE_ACTIVATION_ERROR_FATAL_BIT (1<<0) ++ ++/** ++ * Type used to represent a point on a timeline. ++ */ ++typedef u32 mali_timeline_point; ++ ++/** ++ * Used to represent that no point on a timeline. ++ */ ++#define MALI_TIMELINE_NO_POINT ((mali_timeline_point) 0) ++ ++/** ++ * The maximum span of points on a timeline. A timeline will be considered full if the difference ++ * between the oldest and newest points is equal or larger to this value. ++ */ ++#define MALI_TIMELINE_MAX_POINT_SPAN 65536 ++ ++/** ++ * Magic value used to assert on validity of trackers. ++ */ ++#define MALI_TIMELINE_TRACKER_MAGIC 0xabcdabcd ++ ++struct mali_timeline; ++struct mali_timeline_waiter; ++struct mali_timeline_tracker; ++ ++/** ++ * Timeline fence. ++ */ ++struct mali_timeline_fence { ++ mali_timeline_point points[MALI_TIMELINE_MAX]; /**< For each timeline, a point or MALI_TIMELINE_NO_POINT. */ ++ s32 sync_fd; /**< A file descriptor representing a sync fence, or -1. */ ++}; ++ ++/** ++ * Timeline system. ++ * ++ * The Timeline system has a set of timelines associated with a session. ++ */ ++struct mali_timeline_system { ++ struct mali_spinlock_reentrant *spinlock; /**< Spin lock protecting the timeline system */ ++ struct mali_timeline *timelines[MALI_TIMELINE_MAX]; /**< The timelines in this system */ ++ ++ /* Single-linked list of unused waiter objects. Uses the tracker_next field in tracker. */ ++ struct mali_timeline_waiter *waiter_empty_list; ++ ++ struct mali_session_data *session; /**< Session that owns this system. */ ++ ++ mali_bool timer_enabled; /**< Set to MALI_TRUE if soft job timer should be enabled, MALI_FALSE if not. */ ++ ++ _mali_osk_wait_queue_t *wait_queue; /**< Wait queue. */ ++ ++#if defined(CONFIG_SYNC) ++ struct sync_timeline *signaled_sync_tl; /**< Special sync timeline used to create pre-signaled sync fences */ ++#endif /* defined(CONFIG_SYNC) */ ++}; ++ ++/** ++ * Timeline. Each Timeline system will have MALI_TIMELINE_MAX timelines. ++ */ ++struct mali_timeline { ++ mali_timeline_point point_next; /**< The next available point. */ ++ mali_timeline_point point_oldest; /**< The oldest point not released. */ ++ ++ /* Double-linked list of trackers. Sorted in ascending order by tracker->time_number with ++ * tail pointing to the tracker with the oldest time. */ ++ struct mali_timeline_tracker *tracker_head; ++ struct mali_timeline_tracker *tracker_tail; ++ ++ /* Double-linked list of waiters. Sorted in ascending order by waiter->time_number_wait ++ * with tail pointing to the waiter with oldest wait time. */ ++ struct mali_timeline_waiter *waiter_head; ++ struct mali_timeline_waiter *waiter_tail; ++ ++ struct mali_timeline_system *system; /**< Timeline system this timeline belongs to. */ ++ enum mali_timeline_id id; /**< Timeline type. */ ++ ++#if defined(CONFIG_SYNC) ++ struct sync_timeline *sync_tl; /**< Sync timeline that corresponds to this timeline. */ ++#endif /* defined(CONFIG_SYNC) */ ++ ++ /* The following fields are used to time out soft job trackers. */ ++ _mali_osk_wq_delayed_work_t *delayed_work; ++ mali_bool timer_active; ++}; ++ ++/** ++ * Timeline waiter. ++ */ ++struct mali_timeline_waiter { ++ mali_timeline_point point; /**< Point on timeline we are waiting for to be released. */ ++ struct mali_timeline_tracker *tracker; /**< Tracker that is waiting. */ ++ ++ struct mali_timeline_waiter *timeline_next; /**< Next waiter on timeline's waiter list. */ ++ struct mali_timeline_waiter *timeline_prev; /**< Previous waiter on timeline's waiter list. */ ++ ++ struct mali_timeline_waiter *tracker_next; /**< Next waiter on tracker's waiter list. */ ++}; ++ ++/** ++ * Timeline tracker. ++ */ ++struct mali_timeline_tracker { ++ MALI_DEBUG_CODE(u32 magic); /**< Should always be MALI_TIMELINE_TRACKER_MAGIC for a valid tracker. */ ++ ++ mali_timeline_point point; /**< Point on timeline for this tracker */ ++ ++ struct mali_timeline_tracker *timeline_next; /**< Next tracker on timeline's tracker list */ ++ struct mali_timeline_tracker *timeline_prev; /**< Previous tracker on timeline's tracker list */ ++ ++ u32 trigger_ref_count; /**< When zero tracker will be activated */ ++ mali_timeline_activation_error activation_error; /**< Activation error. */ ++ struct mali_timeline_fence fence; /**< Fence used to create this tracker */ ++ ++ /* Single-linked list of waiters. Sorted in order of insertions with ++ * tail pointing to first waiter. */ ++ struct mali_timeline_waiter *waiter_head; ++ struct mali_timeline_waiter *waiter_tail; ++ ++#if defined(CONFIG_SYNC) ++ /* These are only used if the tracker is waiting on a sync fence. */ ++ struct mali_timeline_waiter *waiter_sync; /**< A direct pointer to timeline waiter representing sync fence. */ ++ struct sync_fence_waiter sync_fence_waiter; /**< Used to connect sync fence and tracker in sync fence wait callback. */ ++ struct sync_fence *sync_fence; /**< The sync fence this tracker is waiting on. */ ++ _mali_osk_list_t sync_fence_cancel_list; /**< List node used to cancel sync fence waiters. */ ++#endif /* defined(CONFIG_SYNC) */ ++ ++ struct mali_timeline_system *system; /**< Timeline system. */ ++ struct mali_timeline *timeline; /**< Timeline, or NULL if not on a timeline. */ ++ enum mali_timeline_tracker_type type; /**< Type of tracker. */ ++ void *job; /**< Owner of tracker. */ ++ ++ /* The following fields are used to time out soft job trackers. */ ++ u32 os_tick_create; ++ u32 os_tick_activate; ++ mali_bool timer_active; ++}; ++ ++/** ++ * What follows is a set of functions to check the state of a timeline and to determine where on a ++ * timeline a given point is. Most of these checks will translate the timeline so the oldest point ++ * on the timeline is aligned with zero. Remember that all of these calculation are done on ++ * unsigned integers. ++ * ++ * The following example illustrates the three different states a point can be in. The timeline has ++ * been translated to put the oldest point at zero: ++ * ++ * ++ * ++ * [ point is in forbidden zone ] ++ * 64k wide ++ * MALI_TIMELINE_MAX_POINT_SPAN ++ * ++ * [ point is on timeline ) ( point is released ] ++ * ++ * 0--------------------------##############################--------------------2^32 - 1 ++ * ^ ^ ++ * \ | ++ * oldest point on timeline | ++ * \ ++ * next point on timeline ++ */ ++ ++/** ++ * Compare two timeline points ++ * ++ * Returns true if a is after b, false if a is before or equal to b. ++ * ++ * This funcion ignores MALI_TIMELINE_MAX_POINT_SPAN. Wrapping is supported and ++ * the result will be correct if the points is less then UINT_MAX/2 apart. ++ * ++ * @param a Point on timeline ++ * @param b Point on timeline ++ * @return MALI_TRUE if a is after b ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_point_after(mali_timeline_point a, mali_timeline_point b) ++{ ++ return 0 > ((s32)b) - ((s32)a); ++} ++ ++/** ++ * Check if a point is on timeline. A point is on a timeline if it is greater than, or equal to, ++ * the oldest point, and less than the next point. ++ * ++ * @param timeline Timeline. ++ * @param point Point on timeline. ++ * @return MALI_TRUE if point is on timeline, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_is_point_on(struct mali_timeline *timeline, mali_timeline_point point) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point); ++ ++ return (point - timeline->point_oldest) < (timeline->point_next - timeline->point_oldest); ++} ++ ++/** ++ * Check if a point has been released. A point is released if it is older than the oldest point on ++ * the timeline, newer than the next point, and also not in the forbidden zone. ++ * ++ * @param timeline Timeline. ++ * @param point Point on timeline. ++ * @return MALI_TRUE if point has been release, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_is_point_released(struct mali_timeline *timeline, mali_timeline_point point) ++{ ++ mali_timeline_point point_normalized; ++ mali_timeline_point next_normalized; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point); ++ ++ point_normalized = point - timeline->point_oldest; ++ next_normalized = timeline->point_next - timeline->point_oldest; ++ ++ return point_normalized > (next_normalized + MALI_TIMELINE_MAX_POINT_SPAN); ++} ++ ++/** ++ * Check if a point is valid. A point is valid if is on the timeline or has been released. ++ * ++ * @param timeline Timeline. ++ * @param point Point on timeline. ++ * @return MALI_TRUE if point is valid, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_is_point_valid(struct mali_timeline *timeline, mali_timeline_point point) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ return mali_timeline_is_point_on(timeline, point) || mali_timeline_is_point_released(timeline, point); ++} ++ ++/** ++ * Check if timeline is empty (has no points on it). A timeline is empty if next == oldest. ++ * ++ * @param timeline Timeline. ++ * @return MALI_TRUE if timeline is empty, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_is_empty(struct mali_timeline *timeline) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ return timeline->point_next == timeline->point_oldest; ++} ++ ++/** ++ * Check if timeline is full. A valid timeline cannot span more than 64k points (@ref ++ * MALI_TIMELINE_MAX_POINT_SPAN). ++ * ++ * @param timeline Timeline. ++ * @return MALI_TRUE if timeline is full, MALI_FALSE if not. ++ */ ++MALI_STATIC_INLINE mali_bool mali_timeline_is_full(struct mali_timeline *timeline) ++{ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ return MALI_TIMELINE_MAX_POINT_SPAN <= (timeline->point_next - timeline->point_oldest); ++} ++ ++/** ++ * Create a new timeline system. ++ * ++ * @param session The session this timeline system will belong to. ++ * @return New timeline system. ++ */ ++struct mali_timeline_system *mali_timeline_system_create(struct mali_session_data *session); ++ ++/** ++ * Abort timeline system. ++ * ++ * This will release all pending waiters in the timeline system causing all trackers to be ++ * activated. ++ * ++ * @param system Timeline system to abort all jobs from. ++ */ ++void mali_timeline_system_abort(struct mali_timeline_system *system); ++ ++/** ++ * Destroy an empty timeline system. ++ * ++ * @note @ref mali_timeline_system_abort() should be called prior to this function. ++ * ++ * @param system Timeline system to destroy. ++ */ ++void mali_timeline_system_destroy(struct mali_timeline_system *system); ++ ++/** ++ * Stop the soft job timer. ++ * ++ * @param system Timeline system ++ */ ++void mali_timeline_system_stop_timer(struct mali_timeline_system *system); ++ ++/** ++ * Add a tracker to a timeline system and optionally also on a timeline. ++ * ++ * Once added to the timeline system, the tracker is guaranteed to be activated. The tracker can be ++ * activated before this function returns. Thus, it is also possible that the tracker is released ++ * before this function returns, depending on the tracker type. ++ * ++ * @note Tracker must be initialized (@ref mali_timeline_tracker_init) before being added to the ++ * timeline system. ++ * ++ * @param system Timeline system the tracker will be added to. ++ * @param tracker The tracker to be added. ++ * @param timeline_id Id of the timeline the tracker will be added to, or ++ * MALI_TIMELINE_NONE if it should not be added on a timeline. ++ * @return Point on timeline identifying this tracker, or MALI_TIMELINE_NO_POINT if not on timeline. ++ */ ++mali_timeline_point mali_timeline_system_add_tracker(struct mali_timeline_system *system, ++ struct mali_timeline_tracker *tracker, ++ enum mali_timeline_id timeline_id); ++ ++/** ++ * Get latest point on timeline. ++ * ++ * @param system Timeline system. ++ * @param timeline_id Id of timeline to get latest point from. ++ * @return Latest point on timeline, or MALI_TIMELINE_NO_POINT if the timeline is empty. ++ */ ++mali_timeline_point mali_timeline_system_get_latest_point(struct mali_timeline_system *system, ++ enum mali_timeline_id timeline_id); ++ ++/** ++ * Initialize tracker. ++ * ++ * Must be called before tracker is added to timeline system (@ref mali_timeline_system_add_tracker). ++ * ++ * @param tracker Tracker to initialize. ++ * @param type Type of tracker. ++ * @param fence Fence used to set up dependencies for tracker. ++ * @param job Pointer to job struct this tracker is associated with. ++ */ ++void mali_timeline_tracker_init(struct mali_timeline_tracker *tracker, ++ mali_timeline_tracker_type type, ++ struct mali_timeline_fence *fence, ++ void *job); ++ ++/** ++ * Grab trigger ref count on tracker. ++ * ++ * This will prevent tracker from being activated until the trigger ref count reaches zero. ++ * ++ * @note Tracker must have been initialized (@ref mali_timeline_tracker_init). ++ * ++ * @param system Timeline system. ++ * @param tracker Tracker. ++ */ ++void mali_timeline_system_tracker_get(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker); ++ ++/** ++ * Release trigger ref count on tracker. ++ * ++ * If the trigger ref count reaches zero, the tracker will be activated. ++ * ++ * @param system Timeline system. ++ * @param tracker Tracker. ++ * @param activation_error Error bitmask if activated with error, or MALI_TIMELINE_ACTIVATION_ERROR_NONE if no error. ++ * @return Scheduling bitmask. ++ */ ++mali_scheduler_mask mali_timeline_system_tracker_put(struct mali_timeline_system *system, struct mali_timeline_tracker *tracker, mali_timeline_activation_error activation_error); ++ ++/** ++ * Release a tracker from the timeline system. ++ * ++ * This is used to signal that the job being tracker is finished, either due to normal circumstances ++ * (job complete/abort) or due to a timeout. ++ * ++ * We may need to schedule some subsystems after a tracker has been released and the returned ++ * bitmask will tell us if it is necessary. If the return value is non-zero, this value needs to be ++ * sent as an input parameter to @ref mali_scheduler_schedule_from_mask() to do the scheduling. ++ * ++ * @note Tracker must have been activated before being released. ++ * @warning Not calling @ref mali_scheduler_schedule_from_mask() after releasing a tracker can lead ++ * to a deadlock. ++ * ++ * @param tracker Tracker being released. ++ * @return Scheduling bitmask. ++ */ ++mali_scheduler_mask mali_timeline_tracker_release(struct mali_timeline_tracker *tracker); ++ ++/** ++ * Copy data from a UK fence to a Timeline fence. ++ * ++ * @param fence Timeline fence. ++ * @param uk_fence UK fence. ++ */ ++void mali_timeline_fence_copy_uk_fence(struct mali_timeline_fence *fence, _mali_uk_fence_t *uk_fence); ++ ++#define MALI_TIMELINE_DEBUG_FUNCTIONS ++#if defined(MALI_TIMELINE_DEBUG_FUNCTIONS) ++ ++/** ++ * Tracker state. Used for debug printing. ++ */ ++typedef enum mali_timeline_tracker_state { ++ MALI_TIMELINE_TS_INIT = 0, ++ MALI_TIMELINE_TS_WAITING = 1, ++ MALI_TIMELINE_TS_ACTIVE = 2, ++ MALI_TIMELINE_TS_FINISH = 3, ++} mali_timeline_tracker_state; ++ ++/** ++ * Get tracker state. ++ * ++ * @param tracker Tracker to check. ++ * @return State of tracker. ++ */ ++mali_timeline_tracker_state mali_timeline_debug_get_tracker_state(struct mali_timeline_tracker *tracker); ++ ++/** ++ * Print debug information about tracker. ++ * ++ * @param tracker Tracker to print. ++ */ ++void mali_timeline_debug_print_tracker(struct mali_timeline_tracker *tracker); ++ ++/** ++ * Print debug information about timeline. ++ * ++ * @param timeline Timeline to print. ++ */ ++void mali_timeline_debug_print_timeline(struct mali_timeline *timeline); ++ ++/** ++ * Print debug information about timeline system. ++ * ++ * @param system Timeline system to print. ++ */ ++void mali_timeline_debug_print_system(struct mali_timeline_system *system); ++ ++#endif /* defined(MALI_TIMELINE_DEBUG_FUNCTIONS) */ ++ ++#endif /* __MALI_TIMELINE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.c +new file mode 100644 +index 0000000..752bec7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.c +@@ -0,0 +1,198 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_timeline_fence_wait.h" ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_spinlock_reentrant.h" ++ ++/** ++ * Allocate a fence waiter tracker. ++ * ++ * @return New fence waiter if successful, NULL if not. ++ */ ++static struct mali_timeline_fence_wait_tracker *mali_timeline_fence_wait_tracker_alloc(void) ++{ ++ return (struct mali_timeline_fence_wait_tracker *) _mali_osk_calloc(1, sizeof(struct mali_timeline_fence_wait_tracker)); ++} ++ ++/** ++ * Free fence waiter tracker. ++ * ++ * @param wait Fence wait tracker to free. ++ */ ++static void mali_timeline_fence_wait_tracker_free(struct mali_timeline_fence_wait_tracker *wait) ++{ ++ MALI_DEBUG_ASSERT_POINTER(wait); ++ _mali_osk_atomic_term(&wait->refcount); ++ _mali_osk_free(wait); ++} ++ ++/** ++ * Check if fence wait tracker has been activated. Used as a wait queue condition. ++ * ++ * @param data Fence waiter. ++ * @return MALI_TRUE if tracker has been activated, MALI_FALSE if not. ++ */ ++static mali_bool mali_timeline_fence_wait_tracker_is_activated(void *data) ++{ ++ struct mali_timeline_fence_wait_tracker *wait; ++ ++ wait = (struct mali_timeline_fence_wait_tracker *) data; ++ MALI_DEBUG_ASSERT_POINTER(wait); ++ ++ return wait->activated; ++} ++ ++/** ++ * Check if fence has been signaled. ++ * ++ * @param system Timeline system. ++ * @param fence Timeline fence. ++ * @return MALI_TRUE if fence is signaled, MALI_FALSE if not. ++ */ ++static mali_bool mali_timeline_fence_wait_check_status(struct mali_timeline_system *system, struct mali_timeline_fence *fence) ++{ ++ int i; ++ u32 tid = _mali_osk_get_tid(); ++ mali_bool ret = MALI_TRUE; ++#if defined(CONFIG_SYNC) ++ struct sync_fence *sync_fence = NULL; ++#endif ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ ++ mali_spinlock_reentrant_wait(system->spinlock, tid); ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline; ++ mali_timeline_point point; ++ ++ point = fence->points[i]; ++ ++ if (likely(MALI_TIMELINE_NO_POINT == point)) { ++ /* Fence contains no point on this timeline. */ ++ continue; ++ } ++ ++ timeline = system->timelines[i]; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ if (unlikely(!mali_timeline_is_point_valid(timeline, point))) { ++ MALI_PRINT_ERROR(("Mali Timeline: point %d is not valid (oldest=%d, next=%d)\n", point, timeline->point_oldest, timeline->point_next)); ++ } ++ ++ if (!mali_timeline_is_point_released(timeline, point)) { ++ ret = MALI_FALSE; ++ goto exit; ++ } ++ } ++ ++#if defined(CONFIG_SYNC) ++ if (-1 != fence->sync_fd) { ++ sync_fence = sync_fence_fdget(fence->sync_fd); ++ if (likely(NULL != sync_fence)) { ++ if (0 == sync_fence->status) { ++ ret = MALI_FALSE; ++ } ++ } else { ++ MALI_PRINT_ERROR(("Mali Timeline: failed to get sync fence from fd %d\n", fence->sync_fd)); ++ } ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++exit: ++ mali_spinlock_reentrant_signal(system->spinlock, tid); ++ ++#if defined(CONFIG_SYNC) ++ if (NULL != sync_fence) { ++ sync_fence_put(sync_fence); ++ } ++#endif /* defined(CONFIG_SYNC) */ ++ ++ return ret; ++} ++ ++mali_bool mali_timeline_fence_wait(struct mali_timeline_system *system, struct mali_timeline_fence *fence, u32 timeout) ++{ ++ struct mali_timeline_fence_wait_tracker *wait; ++ mali_timeline_point point; ++ mali_bool ret; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: wait on fence\n")); ++ ++ if (MALI_TIMELINE_FENCE_WAIT_TIMEOUT_IMMEDIATELY == timeout) { ++ return mali_timeline_fence_wait_check_status(system, fence); ++ } ++ ++ wait = mali_timeline_fence_wait_tracker_alloc(); ++ if (unlikely(NULL == wait)) { ++ MALI_PRINT_ERROR(("Mali Timeline: failed to allocate data for fence wait\n")); ++ return MALI_FALSE; ++ } ++ ++ wait->activated = MALI_FALSE; ++ wait->system = system; ++ ++ /* Initialize refcount to two references. The reference first will be released by this ++ * function after the wait is over. The second reference will be released when the tracker ++ * is activated. */ ++ _mali_osk_atomic_init(&wait->refcount, 2); ++ ++ /* Add tracker to timeline system, but not to a timeline. */ ++ mali_timeline_tracker_init(&wait->tracker, MALI_TIMELINE_TRACKER_WAIT, fence, wait); ++ point = mali_timeline_system_add_tracker(system, &wait->tracker, MALI_TIMELINE_NONE); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT == point); ++ MALI_IGNORE(point); ++ ++ /* Wait for the tracker to be activated or time out. */ ++ if (MALI_TIMELINE_FENCE_WAIT_TIMEOUT_NEVER == timeout) { ++ _mali_osk_wait_queue_wait_event(system->wait_queue, mali_timeline_fence_wait_tracker_is_activated, (void *) wait); ++ } else { ++ _mali_osk_wait_queue_wait_event_timeout(system->wait_queue, mali_timeline_fence_wait_tracker_is_activated, (void *) wait, timeout); ++ } ++ ++ ret = wait->activated; ++ ++ if (0 == _mali_osk_atomic_dec_return(&wait->refcount)) { ++ mali_timeline_fence_wait_tracker_free(wait); ++ } ++ ++ return ret; ++} ++ ++void mali_timeline_fence_wait_activate(struct mali_timeline_fence_wait_tracker *wait) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(wait); ++ MALI_DEBUG_ASSERT_POINTER(wait->system); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: activation for fence wait tracker\n")); ++ ++ MALI_DEBUG_ASSERT(MALI_FALSE == wait->activated); ++ wait->activated = MALI_TRUE; ++ ++ _mali_osk_wait_queue_wake_up(wait->system->wait_queue); ++ ++ /* Nothing can wait on this tracker, so nothing to schedule after release. */ ++ schedule_mask = mali_timeline_tracker_release(&wait->tracker); ++ MALI_DEBUG_ASSERT(MALI_SCHEDULER_MASK_EMPTY == schedule_mask); ++ MALI_IGNORE(schedule_mask); ++ ++ if (0 == _mali_osk_atomic_dec_return(&wait->refcount)) { ++ mali_timeline_fence_wait_tracker_free(wait); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.h +new file mode 100644 +index 0000000..b73e608 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_fence_wait.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_timeline_fence_wait.h ++ * ++ * This file contains functions used to wait until a Timeline fence is signaled. ++ */ ++ ++#ifndef __MALI_TIMELINE_FENCE_WAIT_H__ ++#define __MALI_TIMELINE_FENCE_WAIT_H__ ++ ++#include "mali_osk.h" ++#include "mali_timeline.h" ++ ++/** ++ * If used as the timeout argument in @ref mali_timeline_fence_wait, a timer is not used and the ++ * function only returns when the fence is signaled. ++ */ ++#define MALI_TIMELINE_FENCE_WAIT_TIMEOUT_NEVER ((u32) -1) ++ ++/** ++ * If used as the timeout argument in @ref mali_timeline_fence_wait, the function will return ++ * immediately with the current state of the fence. ++ */ ++#define MALI_TIMELINE_FENCE_WAIT_TIMEOUT_IMMEDIATELY 0 ++ ++/** ++ * Fence wait tracker. ++ * ++ * The fence wait tracker is added to the Timeline system with the fence we are waiting on as a ++ * dependency. We will then perform a blocking wait, possibly with a timeout, until the tracker is ++ * activated, which happens when the fence is signaled. ++ */ ++struct mali_timeline_fence_wait_tracker { ++ mali_bool activated; /**< MALI_TRUE if the tracker has been activated, MALI_FALSE if not. */ ++ _mali_osk_atomic_t refcount; /**< Reference count. */ ++ struct mali_timeline_system *system; /**< Timeline system. */ ++ struct mali_timeline_tracker tracker; /**< Timeline tracker. */ ++}; ++ ++/** ++ * Wait for a fence to be signaled, or timeout is reached. ++ * ++ * @param system Timeline system. ++ * @param fence Fence to wait on. ++ * @param timeout Timeout in ms, or MALI_TIMELINE_FENCE_WAIT_TIMEOUT_NEVER or ++ * MALI_TIMELINE_FENCE_WAIT_TIMEOUT_IMMEDIATELY. ++ * @return MALI_TRUE if signaled, MALI_FALSE if timed out. ++ */ ++mali_bool mali_timeline_fence_wait(struct mali_timeline_system *system, struct mali_timeline_fence *fence, u32 timeout); ++ ++/** ++ * Used by the Timeline system to activate a fence wait tracker. ++ * ++ * @param fence_wait_tracker Fence waiter tracker. ++ */ ++void mali_timeline_fence_wait_activate(struct mali_timeline_fence_wait_tracker *fence_wait_tracker); ++ ++#endif /* __MALI_TIMELINE_FENCE_WAIT_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.c +new file mode 100644 +index 0000000..c1ad291 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.c +@@ -0,0 +1,158 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_timeline_sync_fence.h" ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_sync.h" ++ ++#if defined(CONFIG_SYNC) ++ ++/** ++ * Creates a sync fence tracker and a sync fence. Adds sync fence tracker to Timeline system and ++ * returns sync fence. The sync fence will be signaled when the sync fence tracker is activated. ++ * ++ * @param timeline Timeline. ++ * @param point Point on timeline. ++ * @return Sync fence that will be signaled when tracker is activated. ++ */ ++static struct sync_fence *mali_timeline_sync_fence_create_and_add_tracker(struct mali_timeline *timeline, mali_timeline_point point) ++{ ++ struct mali_timeline_sync_fence_tracker *sync_fence_tracker; ++ struct sync_fence *sync_fence; ++ struct mali_timeline_fence fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT != point); ++ ++ /* Allocate sync fence tracker. */ ++ sync_fence_tracker = _mali_osk_calloc(1, sizeof(struct mali_timeline_sync_fence_tracker)); ++ if (NULL == sync_fence_tracker) { ++ MALI_PRINT_ERROR(("Mali Timeline: sync_fence_tracker allocation failed\n")); ++ return NULL; ++ } ++ ++ /* Create sync flag. */ ++ MALI_DEBUG_ASSERT_POINTER(timeline->sync_tl); ++ sync_fence_tracker->flag = mali_sync_flag_create(timeline->sync_tl, point); ++ if (NULL == sync_fence_tracker->flag) { ++ MALI_PRINT_ERROR(("Mali Timeline: sync_flag creation failed\n")); ++ _mali_osk_free(sync_fence_tracker); ++ return NULL; ++ } ++ ++ /* Create sync fence from sync flag. */ ++ sync_fence = mali_sync_flag_create_fence(sync_fence_tracker->flag); ++ if (NULL == sync_fence) { ++ MALI_PRINT_ERROR(("Mali Timeline: sync_fence creation failed\n")); ++ mali_sync_flag_put(sync_fence_tracker->flag); ++ _mali_osk_free(sync_fence_tracker); ++ return NULL; ++ } ++ ++ /* Setup fence for tracker. */ ++ _mali_osk_memset(&fence, 0, sizeof(struct mali_timeline_fence)); ++ fence.sync_fd = -1; ++ fence.points[timeline->id] = point; ++ ++ /* Finally, add the tracker to Timeline system. */ ++ mali_timeline_tracker_init(&sync_fence_tracker->tracker, MALI_TIMELINE_TRACKER_SYNC, &fence, sync_fence_tracker); ++ point = mali_timeline_system_add_tracker(timeline->system, &sync_fence_tracker->tracker, MALI_TIMELINE_NONE); ++ MALI_DEBUG_ASSERT(MALI_TIMELINE_NO_POINT == point); ++ ++ return sync_fence; ++} ++ ++s32 mali_timeline_sync_fence_create(struct mali_timeline_system *system, struct mali_timeline_fence *fence) ++{ ++ u32 i; ++ struct sync_fence *sync_fence_acc = NULL; ++ ++ MALI_DEBUG_ASSERT_POINTER(system); ++ MALI_DEBUG_ASSERT_POINTER(fence); ++ ++ for (i = 0; i < MALI_TIMELINE_MAX; ++i) { ++ struct mali_timeline *timeline; ++ struct sync_fence *sync_fence; ++ ++ if (MALI_TIMELINE_NO_POINT == fence->points[i]) continue; ++ ++ timeline = system->timelines[i]; ++ MALI_DEBUG_ASSERT_POINTER(timeline); ++ ++ sync_fence = mali_timeline_sync_fence_create_and_add_tracker(timeline, fence->points[i]); ++ if (NULL == sync_fence) goto error; ++ ++ if (NULL != sync_fence_acc) { ++ /* Merge sync fences. */ ++ sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence); ++ if (NULL == sync_fence_acc) goto error; ++ } else { ++ /* This was the first sync fence created. */ ++ sync_fence_acc = sync_fence; ++ } ++ } ++ ++ if (-1 != fence->sync_fd) { ++ struct sync_fence *sync_fence; ++ ++ sync_fence = sync_fence_fdget(fence->sync_fd); ++ if (NULL == sync_fence) goto error; ++ ++ if (NULL != sync_fence_acc) { ++ sync_fence_acc = mali_sync_fence_merge(sync_fence_acc, sync_fence); ++ if (NULL == sync_fence_acc) goto error; ++ } else { ++ sync_fence_acc = sync_fence; ++ } ++ } ++ ++ if (NULL == sync_fence_acc) { ++ MALI_DEBUG_ASSERT_POINTER(system->signaled_sync_tl); ++ ++ /* There was nothing to wait on, so return an already signaled fence. */ ++ ++ sync_fence_acc = mali_sync_timeline_create_signaled_fence(system->signaled_sync_tl); ++ if (NULL == sync_fence_acc) goto error; ++ } ++ ++ /* Return file descriptor for the accumulated sync fence. */ ++ return mali_sync_fence_fd_alloc(sync_fence_acc); ++ ++error: ++ if (NULL != sync_fence_acc) { ++ sync_fence_put(sync_fence_acc); ++ } ++ ++ return -1; ++} ++ ++void mali_timeline_sync_fence_activate(struct mali_timeline_sync_fence_tracker *sync_fence_tracker) ++{ ++ mali_scheduler_mask schedule_mask = MALI_SCHEDULER_MASK_EMPTY; ++ ++ MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker); ++ MALI_DEBUG_ASSERT_POINTER(sync_fence_tracker->flag); ++ ++ MALI_DEBUG_PRINT(4, ("Mali Timeline: activation for sync fence tracker\n")); ++ ++ /* Signal flag and release reference. */ ++ mali_sync_flag_signal(sync_fence_tracker->flag, 0); ++ mali_sync_flag_put(sync_fence_tracker->flag); ++ ++ /* Nothing can wait on this tracker, so nothing to schedule after release. */ ++ schedule_mask = mali_timeline_tracker_release(&sync_fence_tracker->tracker); ++ MALI_DEBUG_ASSERT(MALI_SCHEDULER_MASK_EMPTY == schedule_mask); ++ ++ _mali_osk_free(sync_fence_tracker); ++} ++ ++#endif /* defined(CONFIG_SYNC) */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.h +new file mode 100644 +index 0000000..ec28019 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_timeline_sync_fence.h +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_timeline_sync_fence.h ++ * ++ * This file contains code related to creating sync fences from timeline fences. ++ */ ++ ++#ifndef __MALI_TIMELINE_SYNC_FENCE_H__ ++#define __MALI_TIMELINE_SYNC_FENCE_H__ ++ ++#include "mali_timeline.h" ++ ++#if defined(CONFIG_SYNC) ++ ++/** ++ * Sync fence tracker. ++ */ ++struct mali_timeline_sync_fence_tracker { ++ struct mali_sync_flag *flag; /**< Sync flag used to connect tracker and sync fence. */ ++ struct mali_timeline_tracker tracker; /**< Timeline tracker. */ ++}; ++ ++/** ++ * Create a sync fence that will be signaled when @ref fence is signaled. ++ * ++ * @param system Timeline system. ++ * @param fence Fence to create sync fence from. ++ * @return File descriptor for new sync fence, or -1 on error. ++ */ ++s32 mali_timeline_sync_fence_create(struct mali_timeline_system *system, struct mali_timeline_fence *fence); ++ ++/** ++ * Used by the Timeline system to activate a sync fence tracker. ++ * ++ * @param sync_fence_tracker Sync fence tracker. ++ * ++ */ ++void mali_timeline_sync_fence_activate(struct mali_timeline_sync_fence_tracker *sync_fence_tracker); ++ ++#endif /* defined(CONFIG_SYNC) */ ++ ++#endif /* __MALI_TIMELINE_SYNC_FENCE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_ukk.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_ukk.h +new file mode 100644 +index 0000000..80ef64d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_ukk.h +@@ -0,0 +1,614 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_ukk.h ++ * Defines the kernel-side interface of the user-kernel interface ++ */ ++ ++#ifndef __MALI_UKK_H__ ++#define __MALI_UKK_H__ ++ ++#include "mali_osk.h" ++#include "mali_uk_types.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * @addtogroup uddapi Unified Device Driver (UDD) APIs ++ * ++ * @{ ++ */ ++ ++/** ++ * @addtogroup u_k_api UDD User/Kernel Interface (U/K) APIs ++ * ++ * - The _mali_uk functions are an abstraction of the interface to the device ++ * driver. On certain OSs, this would be implemented via the IOCTL interface. ++ * On other OSs, it could be via extension of some Device Driver Class, or ++ * direct function call for Bare metal/RTOSs. ++ * - It is important to note that: ++ * - The Device Driver has implemented the _mali_ukk set of functions ++ * - The Base Driver calls the corresponding set of _mali_uku functions. ++ * - What requires porting is solely the calling mechanism from User-side to ++ * Kernel-side, and propagating back the results. ++ * - Each U/K function is associated with a (group, number) pair from ++ * \ref _mali_uk_functions to make it possible for a common function in the ++ * Base Driver and Device Driver to route User/Kernel calls from/to the ++ * correct _mali_uk function. For example, in an IOCTL system, the IOCTL number ++ * would be formed based on the group and number assigned to the _mali_uk ++ * function, as listed in \ref _mali_uk_functions. On the user-side, each ++ * _mali_uku function would just make an IOCTL with the IOCTL-code being an ++ * encoded form of the (group, number) pair. On the kernel-side, the Device ++ * Driver's IOCTL handler decodes the IOCTL-code back into a (group, number) ++ * pair, and uses this to determine which corresponding _mali_ukk should be ++ * called. ++ * - Refer to \ref _mali_uk_functions for more information about this ++ * (group, number) pairing. ++ * - In a system where there is no distinction between user and kernel-side, ++ * the U/K interface may be implemented as:@code ++ * MALI_STATIC_INLINE _mali_osk_errcode_t _mali_uku_examplefunction( _mali_uk_examplefunction_s *args ) ++ * { ++ * return mali_ukk_examplefunction( args ); ++ * } ++ * @endcode ++ * - Therefore, all U/K calls behave \em as \em though they were direct ++ * function calls (but the \b implementation \em need \em not be a direct ++ * function calls) ++ * ++ * @note Naming the _mali_uk functions the same on both User and Kernel sides ++ * on non-RTOS systems causes debugging issues when setting breakpoints. In ++ * this case, it is not clear which function the breakpoint is put on. ++ * Therefore the _mali_uk functions in user space are prefixed with \c _mali_uku ++ * and in kernel space with \c _mali_ukk. The naming for the argument ++ * structures is unaffected. ++ * ++ * - The _mali_uk functions are synchronous. ++ * - Arguments to the _mali_uk functions are passed in a structure. The only ++ * parameter passed to the _mali_uk functions is a pointer to this structure. ++ * This first member of this structure, ctx, is a pointer to a context returned ++ * by _mali_uku_open(). For example:@code ++ * typedef struct ++ * { ++ * void *ctx; ++ * u32 number_of_cores; ++ * } _mali_uk_get_gp_number_of_cores_s; ++ * @endcode ++ * ++ * - Each _mali_uk function has its own argument structure named after the ++ * function. The argument is distinguished by the _s suffix. ++ * - The argument types are defined by the base driver and user-kernel ++ * interface. ++ * - All _mali_uk functions return a standard \ref _mali_osk_errcode_t. ++ * - Only arguments of type input or input/output need be initialized before ++ * calling a _mali_uk function. ++ * - Arguments of type output and input/output are only valid when the ++ * _mali_uk function returns \ref _MALI_OSK_ERR_OK. ++ * - The \c ctx member is always invalid after it has been used by a ++ * _mali_uk function, except for the context management functions ++ * ++ * ++ * \b Interface \b restrictions ++ * ++ * The requirements of the interface mean that an implementation of the ++ * User-kernel interface may do no 'real' work. For example, the following are ++ * illegal in the User-kernel implementation: ++ * - Calling functions necessary for operation on all systems, which would ++ * not otherwise get called on RTOS systems. ++ * - For example, a U/K interface that calls multiple _mali_ukk functions ++ * during one particular U/K call. This could not be achieved by the same code ++ * which uses direct function calls for the U/K interface. ++ * - Writing in values to the args members, when otherwise these members would ++ * not hold a useful value for a direct function call U/K interface. ++ * - For example, U/K interface implementation that take NULL members in ++ * their arguments structure from the user side, but those members are ++ * replaced with non-NULL values in the kernel-side of the U/K interface ++ * implementation. A scratch area for writing data is one such example. In this ++ * case, a direct function call U/K interface would segfault, because no code ++ * would be present to replace the NULL pointer with a meaningful pointer. ++ * - Note that we discourage the case where the U/K implementation changes ++ * a NULL argument member to non-NULL, and then the Device Driver code (outside ++ * of the U/K layer) re-checks this member for NULL, and corrects it when ++ * necessary. Whilst such code works even on direct function call U/K ++ * intefaces, it reduces the testing coverage of the Device Driver code. This ++ * is because we have no way of testing the NULL == value path on an OS ++ * implementation. ++ * ++ * A number of allowable examples exist where U/K interfaces do 'real' work: ++ * - The 'pointer switching' technique for \ref _mali_ukk_get_system_info ++ * - In this case, without the pointer switching on direct function call ++ * U/K interface, the Device Driver code still sees the same thing: a pointer ++ * to which it can write memory. This is because such a system has no ++ * distinction between a user and kernel pointer. ++ * - Writing an OS-specific value into the ukk_private member for ++ * _mali_ukk_mem_mmap(). ++ * - In this case, this value is passed around by Device Driver code, but ++ * its actual value is never checked. Device Driver code simply passes it from ++ * the U/K layer to the OSK layer, where it can be acted upon. In this case, ++ * \em some OS implementations of the U/K (_mali_ukk_mem_mmap()) and OSK ++ * (_mali_osk_mem_mapregion_init()) functions will collaborate on the ++ * meaning of ukk_private member. On other OSs, it may be unused by both ++ * U/K and OSK layers ++ * - Therefore, on error inside the U/K interface implementation itself, ++ * it will be as though the _mali_ukk function itself had failed, and cleaned ++ * up after itself. ++ * - Compare this to a direct function call U/K implementation, where all ++ * error cleanup is handled by the _mali_ukk function itself. The direct ++ * function call U/K interface implementation is automatically atomic. ++ * ++ * The last example highlights a consequence of all U/K interface ++ * implementations: they must be atomic with respect to the Device Driver code. ++ * And therefore, should Device Driver code succeed but the U/K implementation ++ * fail afterwards (but before return to user-space), then the U/K ++ * implementation must cause appropriate cleanup actions to preserve the ++ * atomicity of the interface. ++ * ++ * @{ ++ */ ++ ++ ++/** @defgroup _mali_uk_context U/K Context management ++ * ++ * These functions allow for initialisation of the user-kernel interface once per process. ++ * ++ * Generally the context will store the OS specific object to communicate with the kernel device driver and further ++ * state information required by the specific implementation. The context is shareable among all threads in the caller process. ++ * ++ * On IOCTL systems, this is likely to be a file descriptor as a result of opening the kernel device driver. ++ * ++ * On a bare-metal/RTOS system with no distinction between kernel and ++ * user-space, the U/K interface simply calls the _mali_ukk variant of the ++ * function by direct function call. In this case, the context returned is the ++ * mali_session_data from _mali_ukk_open(). ++ * ++ * The kernel side implementations of the U/K interface expect the first member of the argument structure to ++ * be the context created by _mali_uku_open(). On some OS implementations, the meaning of this context ++ * will be different between user-side and kernel-side. In which case, the kernel-side will need to replace this context ++ * with the kernel-side equivalent, because user-side will not have access to kernel-side data. The context parameter ++ * in the argument structure therefore has to be of type input/output. ++ * ++ * It should be noted that the caller cannot reuse the \c ctx member of U/K ++ * argument structure after a U/K call, because it may be overwritten. Instead, ++ * the context handle must always be stored elsewhere, and copied into ++ * the appropriate U/K argument structure for each user-side call to ++ * the U/K interface. This is not usually a problem, since U/K argument ++ * structures are usually placed on the stack. ++ * ++ * @{ */ ++ ++/** @brief Begin a new Mali Device Driver session ++ * ++ * This is used to obtain a per-process context handle for all future U/K calls. ++ * ++ * @param context pointer to storage to return a (void*)context handle. ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_open( void **context ); ++ ++/** @brief End a Mali Device Driver session ++ * ++ * This should be called when the process no longer requires use of the Mali Device Driver. ++ * ++ * The context handle must not be used after it has been closed. ++ * ++ * @param context pointer to a stored (void*)context handle. ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_close( void **context ); ++ ++/** @} */ /* end group _mali_uk_context */ ++ ++ ++/** @addtogroup _mali_uk_core U/K Core ++ * ++ * The core functions provide the following functionality: ++ * - verify that the user and kernel API are compatible ++ * - retrieve information about the cores and memory banks in the system ++ * - wait for the result of jobs started on a core ++ * ++ * @{ */ ++ ++/** @brief Waits for a job notification. ++ * ++ * Sleeps until notified or a timeout occurs. Returns information about the notification. ++ * ++ * @param args see _mali_uk_wait_for_notification_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_wait_for_notification( _mali_uk_wait_for_notification_s *args ); ++ ++/** @brief Post a notification to the notification queue of this application. ++ * ++ * @param args see _mali_uk_post_notification_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_post_notification( _mali_uk_post_notification_s *args ); ++ ++/** @brief Verifies if the user and kernel side of this API are compatible. ++ * ++ * @param args see _mali_uk_get_api_version_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_api_version( _mali_uk_get_api_version_s *args ); ++ ++/** @brief Get the user space settings applicable for calling process. ++ * ++ * @param args see _mali_uk_get_user_settings_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args); ++ ++/** @brief Get a user space setting applicable for calling process. ++ * ++ * @param args see _mali_uk_get_user_setting_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args); ++ ++/* @brief Grant or deny high priority scheduling for this session. ++ * ++ * @param args see _mali_uk_request_high_priority_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_request_high_priority(_mali_uk_request_high_priority_s *args); ++ ++/** @} */ /* end group _mali_uk_core */ ++ ++ ++/** @addtogroup _mali_uk_memory U/K Memory ++ * ++ * The memory functions provide functionality with and without a Mali-MMU present. ++ * ++ * For Mali-MMU based systems, the following functionality is provided: ++ * - Initialize and terminate MALI virtual address space ++ * - Allocate/deallocate physical memory to a MALI virtual address range and map into/unmap from the ++ * current process address space ++ * - Map/unmap external physical memory into the MALI virtual address range ++ * ++ * For Mali-nonMMU based systems: ++ * - Allocate/deallocate MALI memory ++ * ++ * @{ */ ++ ++/** @brief Map Mali Memory into the current user process ++ * ++ * Maps Mali memory into the current user process in a generic way. ++ * ++ * This function is to be used for Mali-MMU mode. The function is available in both Mali-MMU and Mali-nonMMU modes, ++ * but should not be called by a user process in Mali-nonMMU mode. ++ * ++ * The implementation and operation of _mali_ukk_mem_mmap() is dependant on whether the driver is built for Mali-MMU ++ * or Mali-nonMMU: ++ * - In the nonMMU case, _mali_ukk_mem_mmap() requires a physical address to be specified. For this reason, an OS U/K ++ * implementation should not allow this to be called from user-space. In any case, nonMMU implementations are ++ * inherently insecure, and so the overall impact is minimal. Mali-MMU mode should be used if security is desired. ++ * - In the MMU case, _mali_ukk_mem_mmap() the _mali_uk_mem_mmap_s::phys_addr ++ * member is used for the \em Mali-virtual address desired for the mapping. The ++ * implementation of _mali_ukk_mem_mmap() will allocate both the CPU-virtual ++ * and CPU-physical addresses, and can cope with mapping a contiguous virtual ++ * address range to a sequence of non-contiguous physical pages. In this case, ++ * the CPU-physical addresses are not communicated back to the user-side, as ++ * they are unnecsessary; the \em Mali-virtual address range must be used for ++ * programming Mali structures. ++ * ++ * In the second (MMU) case, _mali_ukk_mem_mmap() handles management of ++ * CPU-virtual and CPU-physical ranges, but the \em caller must manage the ++ * \em Mali-virtual address range from the user-side. ++ * ++ * @note Mali-virtual address ranges are entirely separate between processes. ++ * It is not possible for a process to accidentally corrupt another process' ++ * \em Mali-virtual address space. ++ * ++ * @param args see _mali_uk_mem_mmap_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_mem_mmap( _mali_uk_mem_mmap_s *args ); ++ ++/** @brief Unmap Mali Memory from the current user process ++ * ++ * Unmaps Mali memory from the current user process in a generic way. This only operates on Mali memory supplied ++ * from _mali_ukk_mem_mmap(). ++ * ++ * @param args see _mali_uk_mem_munmap_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_mem_munmap( _mali_uk_mem_munmap_s *args ); ++ ++/** @brief Determine the buffer size necessary for an MMU page table dump. ++ * @param args see _mali_uk_query_mmu_page_table_dump_size_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_query_mmu_page_table_dump_size( _mali_uk_query_mmu_page_table_dump_size_s *args ); ++/** @brief Dump MMU Page tables. ++ * @param args see _mali_uk_dump_mmu_page_table_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_dump_mmu_page_table( _mali_uk_dump_mmu_page_table_s * args ); ++ ++/** @brief Write user data to specified Mali memory without causing segfaults. ++ * @param args see _mali_uk_mem_write_safe_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_mem_write_safe( _mali_uk_mem_write_safe_s *args ); ++ ++/** @brief Map a physically contiguous range of memory into Mali ++ * @param args see _mali_uk_map_external_mem_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_map_external_mem( _mali_uk_map_external_mem_s *args ); ++ ++/** @brief Unmap a physically contiguous range of memory from Mali ++ * @param args see _mali_uk_unmap_external_mem_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ); ++ ++#if defined(CONFIG_MALI400_UMP) ++/** @brief Map UMP memory into Mali ++ * @param args see _mali_uk_attach_ump_mem_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_attach_ump_mem( _mali_uk_attach_ump_mem_s *args ); ++/** @brief Unmap UMP memory from Mali ++ * @param args see _mali_uk_release_ump_mem_s in mali_utgard_uk_types.h ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_release_ump_mem( _mali_uk_release_ump_mem_s *args ); ++#endif /* CONFIG_MALI400_UMP */ ++ ++/** @brief Determine virtual-to-physical mapping of a contiguous memory range ++ * (optional) ++ * ++ * This allows the user-side to do a virtual-to-physical address translation. ++ * In conjunction with _mali_uku_map_external_mem, this can be used to do ++ * direct rendering. ++ * ++ * This function will only succeed on a virtual range that is mapped into the ++ * current process, and that is contigious. ++ * ++ * If va is not page-aligned, then it is rounded down to the next page ++ * boundary. The remainer is added to size, such that ((u32)va)+size before ++ * rounding is equal to ((u32)va)+size after rounding. The rounded modified ++ * va and size will be written out into args on success. ++ * ++ * If the supplied size is zero, or not a multiple of the system's PAGE_SIZE, ++ * then size will be rounded up to the next multiple of PAGE_SIZE before ++ * translation occurs. The rounded up size will be written out into args on ++ * success. ++ * ++ * On most OSs, virtual-to-physical address translation is a priveledged ++ * function. Therefore, the implementer must validate the range supplied, to ++ * ensure they are not providing arbitrary virtual-to-physical address ++ * translations. While it is unlikely such a mechanism could be used to ++ * compromise the security of a system on its own, it is possible it could be ++ * combined with another small security risk to cause a much larger security ++ * risk. ++ * ++ * @note This is an optional part of the interface, and is only used by certain ++ * implementations of libEGL. If the platform layer in your libEGL ++ * implementation does not require Virtual-to-Physical address translation, ++ * then this function need not be implemented. A stub implementation should not ++ * be required either, as it would only be removed by the compiler's dead code ++ * elimination. ++ * ++ * @note if implemented, this function is entirely platform-dependant, and does ++ * not exist in common code. ++ * ++ * @param args see _mali_uk_va_to_mali_pa_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_va_to_mali_pa( _mali_uk_va_to_mali_pa_s * args ); ++ ++/** @} */ /* end group _mali_uk_memory */ ++ ++ ++/** @addtogroup _mali_uk_pp U/K Fragment Processor ++ * ++ * The Fragment Processor (aka PP (Pixel Processor)) functions provide the following functionality: ++ * - retrieving version of the fragment processors ++ * - determine number of fragment processors ++ * - starting a job on a fragment processor ++ * ++ * @{ */ ++ ++/** @brief Issue a request to start a new job on a Fragment Processor. ++ * ++ * If the request fails args->status is set to _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE and you can ++ * try to start the job again. ++ * ++ * An existing job could be returned for requeueing if the new job has a higher priority than a previously started job ++ * which the hardware hasn't actually started processing yet. In this case the new job will be started instead and the ++ * existing one returned, otherwise the new job is started and the status field args->status is set to ++ * _MALI_UK_START_JOB_STARTED. ++ * ++ * Job completion can be awaited with _mali_ukk_wait_for_notification(). ++ * ++ * @param ctx user-kernel context (mali_session) ++ * @param uargs see _mali_uk_pp_start_job_s in "mali_utgard_uk_types.h". Use _mali_osk_copy_from_user to retrieve data! ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_pp_start_job( void *ctx, _mali_uk_pp_start_job_s *uargs ); ++ ++/** ++ * @brief Issue a request to start new jobs on both Vertex Processor and Fragment Processor. ++ * ++ * @note Will call into @ref _mali_ukk_pp_start_job and @ref _mali_ukk_gp_start_job. ++ * ++ * @param ctx user-kernel context (mali_session) ++ * @param uargs see _mali_uk_pp_and_gp_start_job_s in "mali_utgard_uk_types.h". Use _mali_osk_copy_from_user to retrieve data! ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_pp_and_gp_start_job( void *ctx, _mali_uk_pp_and_gp_start_job_s *uargs ); ++ ++/** @brief Returns the number of Fragment Processors in the system ++ * ++ * @param args see _mali_uk_get_pp_number_of_cores_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_pp_number_of_cores( _mali_uk_get_pp_number_of_cores_s *args ); ++ ++/** @brief Returns the version that all Fragment Processor cores are compatible with. ++ * ++ * This function may only be called when _mali_ukk_get_pp_number_of_cores() indicated at least one Fragment ++ * Processor core is available. ++ * ++ * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_pp_core_version( _mali_uk_get_pp_core_version_s *args ); ++ ++/** @brief Disable Write-back unit(s) on specified job ++ * ++ * @param args see _mali_uk_get_pp_core_version_s in "mali_utgard_uk_types.h" ++ */ ++void _mali_ukk_pp_job_disable_wb(_mali_uk_pp_disable_wb_s *args); ++ ++ ++/** @} */ /* end group _mali_uk_pp */ ++ ++ ++/** @addtogroup _mali_uk_gp U/K Vertex Processor ++ * ++ * The Vertex Processor (aka GP (Geometry Processor)) functions provide the following functionality: ++ * - retrieving version of the Vertex Processors ++ * - determine number of Vertex Processors available ++ * - starting a job on a Vertex Processor ++ * ++ * @{ */ ++ ++/** @brief Issue a request to start a new job on a Vertex Processor. ++ * ++ * If the request fails args->status is set to _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE and you can ++ * try to start the job again. ++ * ++ * An existing job could be returned for requeueing if the new job has a higher priority than a previously started job ++ * which the hardware hasn't actually started processing yet. In this case the new job will be started and the ++ * existing one returned, otherwise the new job is started and the status field args->status is set to ++ * _MALI_UK_START_JOB_STARTED. ++ * ++ * Job completion can be awaited with _mali_ukk_wait_for_notification(). ++ * ++ * @param ctx user-kernel context (mali_session) ++ * @param uargs see _mali_uk_gp_start_job_s in "mali_utgard_uk_types.h". Use _mali_osk_copy_from_user to retrieve data! ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_gp_start_job( void *ctx, _mali_uk_gp_start_job_s *uargs ); ++ ++/** @brief Returns the number of Vertex Processors in the system. ++ * ++ * @param args see _mali_uk_get_gp_number_of_cores_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_gp_number_of_cores( _mali_uk_get_gp_number_of_cores_s *args ); ++ ++/** @brief Returns the version that all Vertex Processor cores are compatible with. ++ * ++ * This function may only be called when _mali_uk_get_gp_number_of_cores() indicated at least one Vertex ++ * Processor core is available. ++ * ++ * @param args see _mali_uk_get_gp_core_version_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_get_gp_core_version( _mali_uk_get_gp_core_version_s *args ); ++ ++/** @brief Resume or abort suspended Vertex Processor jobs. ++ * ++ * After receiving notification that a Vertex Processor job was suspended from ++ * _mali_ukk_wait_for_notification() you can use this function to resume or abort the job. ++ * ++ * @param args see _mali_uk_gp_suspend_response_s in "mali_utgard_uk_types.h" ++ * @return _MALI_OSK_ERR_OK on success, otherwise a suitable _mali_osk_errcode_t on failure. ++ */ ++_mali_osk_errcode_t _mali_ukk_gp_suspend_response( _mali_uk_gp_suspend_response_s *args ); ++ ++/** @} */ /* end group _mali_uk_gp */ ++ ++#if defined(CONFIG_MALI400_PROFILING) ++/** @addtogroup _mali_uk_profiling U/K Timeline profiling module ++ * @{ */ ++ ++/** @brief Start recording profiling events. ++ * ++ * @param args see _mali_uk_profiling_start_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args); ++ ++/** @brief Add event to profiling buffer. ++ * ++ * @param args see _mali_uk_profiling_add_event_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args); ++ ++/** @brief Stop recording profiling events. ++ * ++ * @param args see _mali_uk_profiling_stop_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args); ++ ++/** @brief Retrieve a recorded profiling event. ++ * ++ * @param args see _mali_uk_profiling_get_event_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args); ++ ++/** @brief Clear recorded profiling events. ++ * ++ * @param args see _mali_uk_profiling_clear_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args); ++ ++/** @} */ /* end group _mali_uk_profiling */ ++#endif ++ ++/** @addtogroup _mali_uk_vsync U/K VSYNC reporting module ++ * @{ */ ++ ++/** @brief Report events related to vsync. ++ * ++ * @note Events should be reported when starting to wait for vsync and when the ++ * waiting is finished. This information can then be used in kernel space to ++ * complement the GPU utilization metric. ++ * ++ * @param args see _mali_uk_vsync_event_report_s in "mali_utgard_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_vsync_event_report(_mali_uk_vsync_event_report_s *args); ++ ++/** @} */ /* end group _mali_uk_vsync */ ++ ++/** @addtogroup _mali_sw_counters_report U/K Software counter reporting ++ * @{ */ ++ ++/** @brief Report software counters. ++ * ++ * @param args see _mali_uk_sw_counters_report_s in "mali_uk_types.h" ++ */ ++_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args); ++ ++/** @} */ /* end group _mali_sw_counters_report */ ++ ++/** @} */ /* end group u_k_api */ ++ ++/** @} */ /* end group uddapi */ ++ ++u32 _mali_ukk_report_memory_usage(void); ++ ++u32 _mali_ukk_utilization_gp_pp(void); ++ ++u32 _mali_ukk_utilization_gp(void); ++ ++u32 _mali_ukk_utilization_pp(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UKK_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.c +new file mode 100644 +index 0000000..e14c91a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.c +@@ -0,0 +1,146 @@ ++/** ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_uk_types.h" ++#include "mali_user_settings_db.h" ++#include "mali_session.h" ++ ++static u32 mali_user_settings[_MALI_UK_USER_SETTING_MAX]; ++const char *_mali_uk_user_setting_descriptions[] = _MALI_UK_USER_SETTING_DESCRIPTIONS; ++ ++static void mali_user_settings_notify(_mali_uk_user_setting_t setting, u32 value) ++{ ++ mali_bool done = MALI_FALSE; ++ ++ /* ++ * This function gets a bit complicated because we can't hold the session lock while ++ * allocating notification objects. ++ */ ++ ++ while (!done) { ++ u32 i; ++ u32 num_sessions_alloc; ++ u32 num_sessions_with_lock; ++ u32 used_notification_objects = 0; ++ _mali_osk_notification_t **notobjs; ++ ++ /* Pre allocate the number of notifications objects we need right now (might change after lock has been taken) */ ++ num_sessions_alloc = mali_session_get_count(); ++ if (0 == num_sessions_alloc) { ++ /* No sessions to report to */ ++ return; ++ } ++ ++ notobjs = (_mali_osk_notification_t **)_mali_osk_malloc(sizeof(_mali_osk_notification_t *) * num_sessions_alloc); ++ if (NULL == notobjs) { ++ MALI_PRINT_ERROR(("Failed to notify user space session about num PP core change (alloc failure)\n")); ++ return; ++ } ++ ++ for (i = 0; i < num_sessions_alloc; i++) { ++ notobjs[i] = _mali_osk_notification_create(_MALI_NOTIFICATION_SETTINGS_CHANGED, ++ sizeof(_mali_uk_settings_changed_s)); ++ if (NULL != notobjs[i]) { ++ _mali_uk_settings_changed_s *data; ++ data = notobjs[i]->result_buffer; ++ ++ data->setting = setting; ++ data->value = value; ++ } else { ++ MALI_PRINT_ERROR(("Failed to notify user space session about setting change (alloc failure %u)\n", i)); ++ } ++ } ++ ++ mali_session_lock(); ++ ++ /* number of sessions will not change while we hold the lock */ ++ num_sessions_with_lock = mali_session_get_count(); ++ ++ if (num_sessions_alloc >= num_sessions_with_lock) { ++ /* We have allocated enough notification objects for all the sessions atm */ ++ struct mali_session_data *session, *tmp; ++ MALI_SESSION_FOREACH(session, tmp, link) { ++ MALI_DEBUG_ASSERT(used_notification_objects < num_sessions_alloc); ++ if (NULL != notobjs[used_notification_objects]) { ++ mali_session_send_notification(session, notobjs[used_notification_objects]); ++ notobjs[used_notification_objects] = NULL; /* Don't track this notification object any more */ ++ } ++ used_notification_objects++; ++ } ++ done = MALI_TRUE; ++ } ++ ++ mali_session_unlock(); ++ ++ /* Delete any remaining/unused notification objects */ ++ for (; used_notification_objects < num_sessions_alloc; used_notification_objects++) { ++ if (NULL != notobjs[used_notification_objects]) { ++ _mali_osk_notification_delete(notobjs[used_notification_objects]); ++ } ++ } ++ ++ _mali_osk_free(notobjs); ++ } ++} ++ ++void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value) ++{ ++ mali_bool notify = MALI_FALSE; ++ ++ if (setting >= _MALI_UK_USER_SETTING_MAX) { ++ MALI_DEBUG_PRINT_ERROR(("Invalid user setting %ud\n")); ++ return; ++ } ++ ++ if (mali_user_settings[setting] != value) { ++ notify = MALI_TRUE; ++ } ++ ++ mali_user_settings[setting] = value; ++ ++ if (notify) { ++ mali_user_settings_notify(setting, value); ++ } ++} ++ ++u32 mali_get_user_setting(_mali_uk_user_setting_t setting) ++{ ++ if (setting >= _MALI_UK_USER_SETTING_MAX) { ++ return 0; ++ } ++ ++ return mali_user_settings[setting]; ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_user_setting(_mali_uk_get_user_setting_s *args) ++{ ++ _mali_uk_user_setting_t setting; ++ MALI_DEBUG_ASSERT_POINTER(args); ++ ++ setting = args->setting; ++ ++ if (_MALI_UK_USER_SETTING_MAX > setting) { ++ args->value = mali_user_settings[setting]; ++ return _MALI_OSK_ERR_OK; ++ } else { ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++} ++ ++_mali_osk_errcode_t _mali_ukk_get_user_settings(_mali_uk_get_user_settings_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ ++ _mali_osk_memcpy(args->settings, mali_user_settings, sizeof(mali_user_settings)); ++ ++ return _MALI_OSK_ERR_OK; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.h +new file mode 100644 +index 0000000..0b51273 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/common/mali_user_settings_db.h +@@ -0,0 +1,39 @@ ++/** ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_USER_SETTINGS_DB_H__ ++#define __MALI_USER_SETTINGS_DB_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "mali_uk_types.h" ++ ++/** @brief Set Mali user setting in DB ++ * ++ * Update the DB with a new value for \a setting. If the value is different from theprevious set value running sessions will be notified of the change. ++ * ++ * @param setting the setting to be changed ++ * @param value the new value to set ++ */ ++void mali_set_user_setting(_mali_uk_user_setting_t setting, u32 value); ++ ++/** @brief Get current Mali user setting value from DB ++ * ++ * @param setting the setting to extract ++ * @return the value of the selected setting ++ */ ++u32 mali_get_user_setting(_mali_uk_user_setting_t setting); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif /* __MALI_KERNEL_USER_SETTING__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard.h +new file mode 100644 +index 0000000..b7a9133 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard.h +@@ -0,0 +1,418 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_utgard.h ++ * Defines types and interface exposed by the Mali Utgard device driver ++ */ ++ ++#ifndef __MALI_UTGARD_H__ ++#define __MALI_UTGARD_H__ ++ ++#include "mali_osk_types.h" ++ ++#define MALI_GPU_NAME_UTGARD "mali-utgard" ++ ++/* Mali-200 */ ++ ++#define MALI_GPU_RESOURCES_MALI200(base_addr, gp_irq, pp_irq, mmu_irq) \ ++ MALI_GPU_RESOURCE_PP(base_addr + 0x0000, pp_irq) \ ++ MALI_GPU_RESOURCE_GP(base_addr + 0x2000, gp_irq) \ ++ MALI_GPU_RESOURCE_MMU(base_addr + 0x3000, mmu_irq) ++ ++/* Mali-300 */ ++ ++#define MALI_GPU_RESOURCES_MALI300(base_addr, gp_irq, gp_mmu_irq, pp_irq, pp_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP1(base_addr, gp_irq, gp_mmu_irq, pp_irq, pp_mmu_irq) ++ ++#define MALI_GPU_RESOURCES_MALI300_PMU(base_addr, gp_irq, gp_mmu_irq, pp_irq, pp_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP1_PMU(base_addr, gp_irq, gp_mmu_irq, pp_irq, pp_mmu_irq) ++ ++/* Mali-400 */ ++ ++#define MALI_GPU_RESOURCES_MALI400_MP1(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x1000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x0000, gp_irq, base_addr + 0x3000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x8000, pp0_irq, base_addr + 0x4000, pp0_mmu_irq) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP1_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP1(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP2(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x1000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x0000, gp_irq, base_addr + 0x3000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x8000, pp0_irq, base_addr + 0x4000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0xA000, pp1_irq, base_addr + 0x5000, pp1_mmu_irq) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP2_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP2(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP3(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x1000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x0000, gp_irq, base_addr + 0x3000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x8000, pp0_irq, base_addr + 0x4000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0xA000, pp1_irq, base_addr + 0x5000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0xC000, pp2_irq, base_addr + 0x6000, pp2_mmu_irq) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP3_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP3(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP4(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x1000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x0000, gp_irq, base_addr + 0x3000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x8000, pp0_irq, base_addr + 0x4000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0xA000, pp1_irq, base_addr + 0x5000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0xC000, pp2_irq, base_addr + 0x6000, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(3, base_addr + 0xE000, pp3_irq, base_addr + 0x7000, pp3_mmu_irq) ++ ++#define MALI_GPU_RESOURCES_MALI400_MP4_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCES_MALI400_MP4(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) ++ ++/* Mali-450 */ ++#define MALI_GPU_RESOURCES_MALI450_MP2(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x10000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x00000, gp_irq, base_addr + 0x03000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x01000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x08000, pp0_irq, base_addr + 0x04000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0x0A000, pp1_irq, base_addr + 0x05000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_BCAST(base_addr + 0x13000) \ ++ MALI_GPU_RESOURCE_DLBU(base_addr + 0x14000) \ ++ MALI_GPU_RESOURCE_PP_BCAST(base_addr + 0x16000, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PP_MMU_BCAST(base_addr + 0x15000) \ ++ MALI_GPU_RESOURCE_DMA(base_addr + 0x12000) ++ ++#define MALI_GPU_RESOURCES_MALI450_MP2_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCES_MALI450_MP2(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) \ ++ ++#define MALI_GPU_RESOURCES_MALI450_MP3(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x10000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x00000, gp_irq, base_addr + 0x03000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x01000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x08000, pp0_irq, base_addr + 0x04000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0x0A000, pp1_irq, base_addr + 0x05000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0x0C000, pp2_irq, base_addr + 0x06000, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_BCAST(base_addr + 0x13000) \ ++ MALI_GPU_RESOURCE_DLBU(base_addr + 0x14000) \ ++ MALI_GPU_RESOURCE_PP_BCAST(base_addr + 0x16000, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PP_MMU_BCAST(base_addr + 0x15000) ++ ++#define MALI_GPU_RESOURCES_MALI450_MP3_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCES_MALI450_MP3(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) \ ++ ++#define MALI_GPU_RESOURCES_MALI450_MP4(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x10000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x00000, gp_irq, base_addr + 0x03000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x01000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x08000, pp0_irq, base_addr + 0x04000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0x0A000, pp1_irq, base_addr + 0x05000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0x0C000, pp2_irq, base_addr + 0x06000, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(3, base_addr + 0x0E000, pp3_irq, base_addr + 0x07000, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCE_BCAST(base_addr + 0x13000) \ ++ MALI_GPU_RESOURCE_DLBU(base_addr + 0x14000) \ ++ MALI_GPU_RESOURCE_PP_BCAST(base_addr + 0x16000, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PP_MMU_BCAST(base_addr + 0x15000) \ ++ MALI_GPU_RESOURCE_DMA(base_addr + 0x12000) ++ ++#define MALI_GPU_RESOURCES_MALI450_MP4_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCES_MALI450_MP4(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) \ ++ ++#define MALI_GPU_RESOURCES_MALI450_MP6(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x10000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x00000, gp_irq, base_addr + 0x03000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x01000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x08000, pp0_irq, base_addr + 0x04000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0x0A000, pp1_irq, base_addr + 0x05000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0x0C000, pp2_irq, base_addr + 0x06000, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x11000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(3, base_addr + 0x28000, pp3_irq, base_addr + 0x1C000, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(4, base_addr + 0x2A000, pp4_irq, base_addr + 0x1D000, pp4_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(5, base_addr + 0x2C000, pp5_irq, base_addr + 0x1E000, pp5_mmu_irq) \ ++ MALI_GPU_RESOURCE_BCAST(base_addr + 0x13000) \ ++ MALI_GPU_RESOURCE_DLBU(base_addr + 0x14000) \ ++ MALI_GPU_RESOURCE_PP_BCAST(base_addr + 0x16000, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PP_MMU_BCAST(base_addr + 0x15000) \ ++ MALI_GPU_RESOURCE_DMA(base_addr + 0x12000) ++ ++#define MALI_GPU_RESOURCES_MALI450_MP6_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCES_MALI450_MP6(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) \ ++ ++#define MALI_GPU_RESOURCES_MALI450_MP8(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp6_irq, pp6_mmu_irq, pp7_irq, pp7_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x10000) \ ++ MALI_GPU_RESOURCE_GP_WITH_MMU(base_addr + 0x00000, gp_irq, base_addr + 0x03000, gp_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x01000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(0, base_addr + 0x08000, pp0_irq, base_addr + 0x04000, pp0_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(1, base_addr + 0x0A000, pp1_irq, base_addr + 0x05000, pp1_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(2, base_addr + 0x0C000, pp2_irq, base_addr + 0x06000, pp2_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(3, base_addr + 0x0E000, pp3_irq, base_addr + 0x07000, pp3_mmu_irq) \ ++ MALI_GPU_RESOURCE_L2(base_addr + 0x11000) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(4, base_addr + 0x28000, pp4_irq, base_addr + 0x1C000, pp4_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(5, base_addr + 0x2A000, pp5_irq, base_addr + 0x1D000, pp5_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(6, base_addr + 0x2C000, pp6_irq, base_addr + 0x1E000, pp6_mmu_irq) \ ++ MALI_GPU_RESOURCE_PP_WITH_MMU(7, base_addr + 0x2E000, pp7_irq, base_addr + 0x1F000, pp7_mmu_irq) \ ++ MALI_GPU_RESOURCE_BCAST(base_addr + 0x13000) \ ++ MALI_GPU_RESOURCE_DLBU(base_addr + 0x14000) \ ++ MALI_GPU_RESOURCE_PP_BCAST(base_addr + 0x16000, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PP_MMU_BCAST(base_addr + 0x15000) \ ++ MALI_GPU_RESOURCE_DMA(base_addr + 0x12000) ++ ++#define MALI_GPU_RESOURCES_MALI450_MP8_PMU(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp6_irq, pp6_mmu_irq, pp7_irq, pp7_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCES_MALI450_MP8(base_addr, gp_irq, gp_mmu_irq, pp0_irq, pp0_mmu_irq, pp1_irq, pp1_mmu_irq, pp2_irq, pp2_mmu_irq, pp3_irq, pp3_mmu_irq, pp4_irq, pp4_mmu_irq, pp5_irq, pp5_mmu_irq, pp6_irq, pp6_mmu_irq, pp7_irq, pp7_mmu_irq, pp_bcast_irq) \ ++ MALI_GPU_RESOURCE_PMU(base_addr + 0x2000) \ ++ ++#define MALI_GPU_RESOURCE_L2(addr) \ ++ { \ ++ .name = "Mali_L2", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = addr, \ ++ .end = addr + 0x200, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_GP(gp_addr, gp_irq) \ ++ { \ ++ .name = "Mali_GP", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = gp_addr, \ ++ .end = gp_addr + 0x100, \ ++ }, \ ++ { \ ++ .name = "Mali_GP_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = gp_irq, \ ++ .end = gp_irq, \ ++ }, \ ++ ++#define MALI_GPU_RESOURCE_GP_WITH_MMU(gp_addr, gp_irq, gp_mmu_addr, gp_mmu_irq) \ ++ { \ ++ .name = "Mali_GP", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = gp_addr, \ ++ .end = gp_addr + 0x100, \ ++ }, \ ++ { \ ++ .name = "Mali_GP_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = gp_irq, \ ++ .end = gp_irq, \ ++ }, \ ++ { \ ++ .name = "Mali_GP_MMU", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = gp_mmu_addr, \ ++ .end = gp_mmu_addr + 0x100, \ ++ }, \ ++ { \ ++ .name = "Mali_GP_MMU_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = gp_mmu_irq, \ ++ .end = gp_mmu_irq, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_PP(pp_addr, pp_irq) \ ++ { \ ++ .name = "Mali_PP", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pp_addr, \ ++ .end = pp_addr + 0x1100, \ ++ }, \ ++ { \ ++ .name = "Mali_PP_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = pp_irq, \ ++ .end = pp_irq, \ ++ }, \ ++ ++#define MALI_GPU_RESOURCE_PP_WITH_MMU(id, pp_addr, pp_irq, pp_mmu_addr, pp_mmu_irq) \ ++ { \ ++ .name = "Mali_PP" #id, \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pp_addr, \ ++ .end = pp_addr + 0x1100, \ ++ }, \ ++ { \ ++ .name = "Mali_PP" #id "_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = pp_irq, \ ++ .end = pp_irq, \ ++ }, \ ++ { \ ++ .name = "Mali_PP" #id "_MMU", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pp_mmu_addr, \ ++ .end = pp_mmu_addr + 0x100, \ ++ }, \ ++ { \ ++ .name = "Mali_PP" #id "_MMU_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = pp_mmu_irq, \ ++ .end = pp_mmu_irq, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_MMU(mmu_addr, mmu_irq) \ ++ { \ ++ .name = "Mali_MMU", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = mmu_addr, \ ++ .end = mmu_addr + 0x100, \ ++ }, \ ++ { \ ++ .name = "Mali_MMU_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = mmu_irq, \ ++ .end = mmu_irq, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_PMU(pmu_addr) \ ++ { \ ++ .name = "Mali_PMU", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pmu_addr, \ ++ .end = pmu_addr + 0x100, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_DMA(dma_addr) \ ++ { \ ++ .name = "Mali_DMA", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = dma_addr, \ ++ .end = dma_addr + 0x100, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_DLBU(dlbu_addr) \ ++ { \ ++ .name = "Mali_DLBU", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = dlbu_addr, \ ++ .end = dlbu_addr + 0x100, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_BCAST(bcast_addr) \ ++ { \ ++ .name = "Mali_Broadcast", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = bcast_addr, \ ++ .end = bcast_addr + 0x100, \ ++ }, ++ ++#define MALI_GPU_RESOURCE_PP_BCAST(pp_addr, pp_irq) \ ++ { \ ++ .name = "Mali_PP_Broadcast", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pp_addr, \ ++ .end = pp_addr + 0x1100, \ ++ }, \ ++ { \ ++ .name = "Mali_PP_Broadcast_IRQ", \ ++ .flags = IORESOURCE_IRQ, \ ++ .start = pp_irq, \ ++ .end = pp_irq, \ ++ }, \ ++ ++#define MALI_GPU_RESOURCE_PP_MMU_BCAST(pp_mmu_bcast_addr) \ ++ { \ ++ .name = "Mali_PP_MMU_Broadcast", \ ++ .flags = IORESOURCE_MEM, \ ++ .start = pp_mmu_bcast_addr, \ ++ .end = pp_mmu_bcast_addr + 0x100, \ ++ }, ++ ++struct mali_gpu_utilization_data { ++ unsigned int utilization_gpu; /* Utilization for GP and all PP cores combined, 0 = no utilization, 256 = full utilization */ ++ unsigned int utilization_gp; /* Utilization for GP core only, 0 = no utilization, 256 = full utilization */ ++ unsigned int utilization_pp; /* Utilization for all PP cores combined, 0 = no utilization, 256 = full utilization */ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++ unsigned int number_of_window_jobs; ++ unsigned int number_of_window_jobs_under_pressure; ++#endif ++}; ++ ++struct mali_gpu_device_data { ++ /* Dedicated GPU memory range (physical). */ ++ unsigned long dedicated_mem_start; ++ unsigned long dedicated_mem_size; ++ ++ /* Shared GPU memory */ ++ unsigned long shared_mem_size; ++ ++ /* Frame buffer memory to be accessible by Mali GPU (physical) */ ++ unsigned long fb_start; ++ unsigned long fb_size; ++ ++ /* Max runtime [ms] for jobs */ ++ int max_job_runtime; ++ ++ /* Report GPU utilization in this interval (specified in ms) */ ++ unsigned long utilization_interval; ++ ++ /* Function that will receive periodic GPU utilization numbers */ ++ void (*utilization_callback)(struct mali_gpu_utilization_data *data); ++ ++ /* ++ * Mali PMU switch delay. ++ * Only needed if the power gates are connected to the PMU in a high fanout ++ * network. This value is the number of Mali clock cycles it takes to ++ * enable the power gates and turn on the power mesh. ++ * This value will have no effect if a daisy chain implementation is used. ++ */ ++ u32 pmu_switch_delay; ++ ++ ++ /* Mali Dynamic power domain configuration in sequence from 0-11 ++ * GP PP0 PP1 PP2 PP3 PP4 PP5 PP6 PP7, L2$0 L2$1 L2$2 ++ */ ++ u16 pmu_domain_config[12]; ++ ++ /* Fuction that platform callback for freq tunning, needed when POWER_PERFORMANCE_POLICY enabled*/ ++ int (*set_freq_callback)(unsigned int mhz); ++}; ++ ++/** @brief MALI GPU power down using MALI in-built PMU ++ * ++ * called to power down all cores ++ */ ++int mali_pmu_powerdown(void); ++ ++ ++/** @brief MALI GPU power up using MALI in-built PMU ++ * ++ * called to power up all cores ++ */ ++int mali_pmu_powerup(void); ++ ++/** ++ * Pause the scheduling and power state changes of Mali device driver. ++ * mali_dev_resume() must always be called as soon as possible after this function ++ * in order to resume normal operation of the Mali driver. ++ */ ++void mali_dev_pause(void); ++ ++/** ++ * Resume scheduling and allow power changes in Mali device driver. ++ * This must always be called after mali_dev_pause(). ++ */ ++void mali_dev_resume(void); ++ ++/** @brief Set the desired number of PP cores to use. ++ * ++ * The internal Mali PMU will be used, if present, to physically power off the PP cores. ++ * ++ * @param num_cores The number of desired cores ++ * @return 0 on success, otherwise error. -EINVAL means an invalid number of cores was specified. ++ */ ++int mali_perf_set_num_pp_cores(unsigned int num_cores); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_counters.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_counters.h +new file mode 100644 +index 0000000..5da13c8 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_counters.h +@@ -0,0 +1,261 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef _MALI_UTGARD_COUNTERS_H_ ++#define _MALI_UTGARD_COUNTERS_H_ ++ ++typedef struct { ++ void *unused; ++} mali_cinstr_counter_info; ++ ++typedef enum { ++ MALI_CINSTR_COUNTER_SOURCE_EGL = 0, ++ MALI_CINSTR_COUNTER_SOURCE_OPENGLES = 1000, ++ MALI_CINSTR_COUNTER_SOURCE_OPENVG = 2000, ++ MALI_CINSTR_COUNTER_SOURCE_GP = 3000, ++ MALI_CINSTR_COUNTER_SOURCE_PP = 4000, ++} cinstr_counter_source; ++ ++#define MALI_CINSTR_EGL_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_EGL ++#define MALI_CINSTR_EGL_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_EGL + 999) ++ ++#define MALI_CINSTR_GLES_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_OPENGLES ++#define MALI_CINSTR_GLES_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 999) ++ ++#define MALI_CINSTR_VG_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_OPENVG ++#define MALI_CINSTR_VG_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_OPENVG + 999) ++ ++#define MALI_CINSTR_GP_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_GP ++#define MALI_CINSTR_GP_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_GP + 999) ++ ++#define MALI_CINSTR_PP_FIRST_COUNTER MALI_CINSTR_COUNTER_SOURCE_PP ++#define MALI_CINSTR_PP_LAST_COUNTER (MALI_CINSTR_COUNTER_SOURCE_PP + 999) ++ ++ ++typedef enum { ++ /* EGL counters */ ++ ++ MALI_CINSTR_EGL_BLIT_TIME = MALI_CINSTR_COUNTER_SOURCE_EGL + 0, ++ ++ /* Last counter in the EGL set */ ++ MALI_CINSTR_EGL_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_EGL + 1, ++ ++ /* GLES counters */ ++ ++ MALI_CINSTR_GLES_DRAW_ELEMENTS_CALLS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 0, ++ MALI_CINSTR_GLES_DRAW_ELEMENTS_NUM_INDICES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 1, ++ MALI_CINSTR_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 2, ++ MALI_CINSTR_GLES_DRAW_ARRAYS_CALLS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 3, ++ MALI_CINSTR_GLES_DRAW_ARRAYS_NUM_TRANSFORMED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 4, ++ MALI_CINSTR_GLES_DRAW_POINTS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 5, ++ MALI_CINSTR_GLES_DRAW_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 6, ++ MALI_CINSTR_GLES_DRAW_LINE_LOOP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 7, ++ MALI_CINSTR_GLES_DRAW_LINE_STRIP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 8, ++ MALI_CINSTR_GLES_DRAW_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 9, ++ MALI_CINSTR_GLES_DRAW_TRIANGLE_STRIP = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 10, ++ MALI_CINSTR_GLES_DRAW_TRIANGLE_FAN = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 11, ++ MALI_CINSTR_GLES_NON_VBO_DATA_COPY_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 12, ++ MALI_CINSTR_GLES_UNIFORM_BYTES_COPIED_TO_MALI = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 13, ++ MALI_CINSTR_GLES_UPLOAD_TEXTURE_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 14, ++ MALI_CINSTR_GLES_UPLOAD_VBO_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 15, ++ MALI_CINSTR_GLES_NUM_FLUSHES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 16, ++ MALI_CINSTR_GLES_NUM_VSHADERS_GENERATED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 17, ++ MALI_CINSTR_GLES_NUM_FSHADERS_GENERATED = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 18, ++ MALI_CINSTR_GLES_VSHADER_GEN_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 19, ++ MALI_CINSTR_GLES_FSHADER_GEN_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 20, ++ MALI_CINSTR_GLES_INPUT_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 21, ++ MALI_CINSTR_GLES_VXCACHE_HIT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 22, ++ MALI_CINSTR_GLES_VXCACHE_MISS = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 23, ++ MALI_CINSTR_GLES_VXCACHE_COLLISION = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 24, ++ MALI_CINSTR_GLES_CULLED_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 25, ++ MALI_CINSTR_GLES_CULLED_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 26, ++ MALI_CINSTR_GLES_BACKFACE_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 27, ++ MALI_CINSTR_GLES_GBCLIP_TRIANGLES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 28, ++ MALI_CINSTR_GLES_GBCLIP_LINES = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 29, ++ MALI_CINSTR_GLES_TRIANGLES_DRAWN = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 30, ++ MALI_CINSTR_GLES_DRAWCALL_TIME = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 31, ++ MALI_CINSTR_GLES_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 32, ++ MALI_CINSTR_GLES_INDEPENDENT_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 33, ++ MALI_CINSTR_GLES_STRIP_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 34, ++ MALI_CINSTR_GLES_FAN_TRIANGLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 35, ++ MALI_CINSTR_GLES_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 36, ++ MALI_CINSTR_GLES_INDEPENDENT_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 37, ++ MALI_CINSTR_GLES_STRIP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 38, ++ MALI_CINSTR_GLES_LOOP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 39, ++ MALI_CINSTR_GLES_POINTS_COUNT = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 40, ++ ++ /* Last counter in the GLES set */ ++ MALI_CINSTR_GLES_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENGLES + 41, ++ ++ /* OpenVG counters */ ++ ++ MALI_CINSTR_VG_MASK_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 0, ++ MALI_CINSTR_VG_CLEAR_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 1, ++ MALI_CINSTR_VG_APPEND_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 2, ++ MALI_CINSTR_VG_APPEND_PATH_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 3, ++ MALI_CINSTR_VG_MODIFY_PATH_COORDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 4, ++ MALI_CINSTR_VG_TRANSFORM_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 5, ++ MALI_CINSTR_VG_INTERPOLATE_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 6, ++ MALI_CINSTR_VG_PATH_LENGTH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 7, ++ MALI_CINSTR_VG_POINT_ALONG_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 8, ++ MALI_CINSTR_VG_PATH_BOUNDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 9, ++ MALI_CINSTR_VG_PATH_TRANSFORMED_BOUNDS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 10, ++ MALI_CINSTR_VG_DRAW_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 11, ++ MALI_CINSTR_VG_CLEAR_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 12, ++ MALI_CINSTR_VG_IMAGE_SUB_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 13, ++ MALI_CINSTR_VG_GET_IMAGE_SUB_DATA_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 14, ++ MALI_CINSTR_VG_COPY_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 15, ++ MALI_CINSTR_VG_DRAW_IMAGE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 16, ++ MALI_CINSTR_VG_SET_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 17, ++ MALI_CINSTR_VG_WRITE_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 18, ++ MALI_CINSTR_VG_GET_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 19, ++ MALI_CINSTR_VG_READ_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 20, ++ MALI_CINSTR_VG_COPY_PIXELS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 21, ++ MALI_CINSTR_VG_COLOR_MATRIX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 22, ++ MALI_CINSTR_VG_CONVOLVE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 23, ++ MALI_CINSTR_VG_SEPARABLE_CONVOLVE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 24, ++ MALI_CINSTR_VG_GAUSSIAN_BLUR_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 25, ++ MALI_CINSTR_VG_LOOKUP_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 26, ++ MALI_CINSTR_VG_LOOKUP_SINGLE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 27, ++ MALI_CINSTR_VG_CONTEXT_CREATE_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 28, ++ MALI_CINSTR_VG_STROKED_CUBICS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 29, ++ MALI_CINSTR_VG_STROKED_QUADS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 30, ++ MALI_CINSTR_VG_STROKED_ARCS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 31, ++ MALI_CINSTR_VG_STROKED_LINES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 32, ++ MALI_CINSTR_VG_FILLED_CUBICS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 33, ++ MALI_CINSTR_VG_FILLED_QUADS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 34, ++ MALI_CINSTR_VG_FILLED_ARCS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 35, ++ MALI_CINSTR_VG_FILLED_LINES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 36, ++ MALI_CINSTR_VG_DRAW_PATH_CALLS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 37, ++ MALI_CINSTR_VG_TRIANGLES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 38, ++ MALI_CINSTR_VG_VERTICES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 39, ++ MALI_CINSTR_VG_INDICES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 40, ++ MALI_CINSTR_VG_FILLED_PATHS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 41, ++ MALI_CINSTR_VG_STROKED_PATHS_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 42, ++ MALI_CINSTR_VG_FILL_EXTRACT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 43, ++ MALI_CINSTR_VG_DRAW_FILLED_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 44, ++ MALI_CINSTR_VG_STROKE_EXTRACT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 45, ++ MALI_CINSTR_VG_DRAW_STROKED_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 46, ++ MALI_CINSTR_VG_DRAW_PAINT_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 47, ++ MALI_CINSTR_VG_DATA_STRUCTURES_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 48, ++ MALI_CINSTR_VG_MEM_PATH_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 49, ++ MALI_CINSTR_VG_RSW_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 50, ++ ++ /* Last counter in the VG set */ ++ MALI_CINSTR_VG_MAX_COUNTER = MALI_CINSTR_COUNTER_SOURCE_OPENVG + 51, ++ ++ /* Mali GP counters */ ++ ++ MALI_CINSTR_GP_DEPRECATED_0 = MALI_CINSTR_COUNTER_SOURCE_GP + 0, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_GP = MALI_CINSTR_COUNTER_SOURCE_GP + 1, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_SHADER = MALI_CINSTR_COUNTER_SOURCE_GP + 2, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_STORER = MALI_CINSTR_COUNTER_SOURCE_GP + 3, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_LOADER = MALI_CINSTR_COUNTER_SOURCE_GP + 4, ++ MALI_CINSTR_GP_CYCLES_VERTEX_LOADER_WAITING_FOR_VERTEX_SHADER = MALI_CINSTR_COUNTER_SOURCE_GP + 5, ++ MALI_CINSTR_GP_NUMBER_OF_WORDS_READ = MALI_CINSTR_COUNTER_SOURCE_GP + 6, ++ MALI_CINSTR_GP_NUMBER_OF_WORDS_WRITTEN = MALI_CINSTR_COUNTER_SOURCE_GP + 7, ++ MALI_CINSTR_GP_NUMBER_OF_READ_BURSTS = MALI_CINSTR_COUNTER_SOURCE_GP + 8, ++ MALI_CINSTR_GP_NUMBER_OF_WRITE_BURSTS = MALI_CINSTR_COUNTER_SOURCE_GP + 9, ++ MALI_CINSTR_GP_NUMBER_OF_VERTICES_PROCESSED = MALI_CINSTR_COUNTER_SOURCE_GP + 10, ++ MALI_CINSTR_GP_NUMBER_OF_VERTICES_FETCHED = MALI_CINSTR_COUNTER_SOURCE_GP + 11, ++ MALI_CINSTR_GP_NUMBER_OF_PRIMITIVES_FETCHED = MALI_CINSTR_COUNTER_SOURCE_GP + 12, ++ MALI_CINSTR_GP_RESERVED_13 = MALI_CINSTR_COUNTER_SOURCE_GP + 13, ++ MALI_CINSTR_GP_NUMBER_OF_BACKFACE_CULLINGS_DONE = MALI_CINSTR_COUNTER_SOURCE_GP + 14, ++ MALI_CINSTR_GP_NUMBER_OF_COMMANDS_WRITTEN_TO_TILES = MALI_CINSTR_COUNTER_SOURCE_GP + 15, ++ MALI_CINSTR_GP_NUMBER_OF_MEMORY_BLOCKS_ALLOCATED = MALI_CINSTR_COUNTER_SOURCE_GP + 16, ++ MALI_CINSTR_GP_RESERVED_17 = MALI_CINSTR_COUNTER_SOURCE_GP + 17, ++ MALI_CINSTR_GP_RESERVED_18 = MALI_CINSTR_COUNTER_SOURCE_GP + 18, ++ MALI_CINSTR_GP_NUMBER_OF_VERTEX_LOADER_CACHE_MISSES = MALI_CINSTR_COUNTER_SOURCE_GP + 19, ++ MALI_CINSTR_GP_RESERVED_20 = MALI_CINSTR_COUNTER_SOURCE_GP + 20, ++ MALI_CINSTR_GP_RESERVED_21 = MALI_CINSTR_COUNTER_SOURCE_GP + 21, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_VERTEX_SHADER_COMMAND_PROCESSOR = MALI_CINSTR_COUNTER_SOURCE_GP + 22, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_COMMAND_PROCESSOR = MALI_CINSTR_COUNTER_SOURCE_GP + 23, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_LIST_WRITER = MALI_CINSTR_COUNTER_SOURCE_GP + 24, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_THROUGH_THE_PREPARE_LIST_COMMANDS = MALI_CINSTR_COUNTER_SOURCE_GP + 25, ++ MALI_CINSTR_GP_RESERVED_26 = MALI_CINSTR_COUNTER_SOURCE_GP + 26, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_PRIMITIVE_ASSEMBLY = MALI_CINSTR_COUNTER_SOURCE_GP + 27, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_VERTEX_FETCHER = MALI_CINSTR_COUNTER_SOURCE_GP + 28, ++ MALI_CINSTR_GP_RESERVED_29 = MALI_CINSTR_COUNTER_SOURCE_GP + 29, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_BOUNDINGBOX_AND_COMMAND_GENERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 30, ++ MALI_CINSTR_GP_RESERVED_31 = MALI_CINSTR_COUNTER_SOURCE_GP + 31, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_SCISSOR_TILE_ITERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 32, ++ MALI_CINSTR_GP_ACTIVE_CYCLES_PLBU_TILE_ITERATOR = MALI_CINSTR_COUNTER_SOURCE_GP + 33, ++ MALI_CINSTR_GP_JOB_COUNT = MALI_CINSTR_COUNTER_SOURCE_GP + 900, ++ ++ /* Mali PP counters */ ++ ++ MALI_CINSTR_PP_ACTIVE_CLOCK_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 0, ++ MALI_CINSTR_PP_TOTAL_CLOCK_CYCLES_COUNT_REMOVED = MALI_CINSTR_COUNTER_SOURCE_PP + 1, ++ MALI_CINSTR_PP_TOTAL_BUS_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 2, ++ MALI_CINSTR_PP_TOTAL_BUS_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 3, ++ MALI_CINSTR_PP_BUS_READ_REQUEST_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 4, ++ MALI_CINSTR_PP_BUS_WRITE_REQUEST_CYCLES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 5, ++ MALI_CINSTR_PP_BUS_READ_TRANSACTIONS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 6, ++ MALI_CINSTR_PP_BUS_WRITE_TRANSACTIONS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 7, ++ MALI_CINSTR_PP_RESERVED_08 = MALI_CINSTR_COUNTER_SOURCE_PP + 8, ++ MALI_CINSTR_PP_TILE_WRITEBACK_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 9, ++ MALI_CINSTR_PP_STORE_UNIT_WRITES = MALI_CINSTR_COUNTER_SOURCE_PP + 10, ++ MALI_CINSTR_PP_RESERVED_11 = MALI_CINSTR_COUNTER_SOURCE_PP + 11, ++ MALI_CINSTR_PP_PALETTE_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 12, ++ MALI_CINSTR_PP_TEXTURE_CACHE_UNCOMPRESSED_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 13, ++ MALI_CINSTR_PP_POLYGON_LIST_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 14, ++ MALI_CINSTR_PP_RSW_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 15, ++ MALI_CINSTR_PP_VERTEX_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 16, ++ MALI_CINSTR_PP_UNIFORM_REMAPPING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 17, ++ MALI_CINSTR_PP_PROGRAM_CACHE_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 18, ++ MALI_CINSTR_PP_VARYING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 19, ++ MALI_CINSTR_PP_TEXTURE_DESCRIPTORS_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 20, ++ MALI_CINSTR_PP_TEXTURE_DESCRIPTORS_REMAPPING_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 21, ++ MALI_CINSTR_PP_TEXTURE_CACHE_COMPRESSED_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 22, ++ MALI_CINSTR_PP_LOAD_UNIT_READS = MALI_CINSTR_COUNTER_SOURCE_PP + 23, ++ MALI_CINSTR_PP_POLYGON_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 24, ++ MALI_CINSTR_PP_PIXEL_RECTANGLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 25, ++ MALI_CINSTR_PP_LINES_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 26, ++ MALI_CINSTR_PP_POINTS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 27, ++ MALI_CINSTR_PP_STALL_CYCLES_POLYGON_LIST_READER = MALI_CINSTR_COUNTER_SOURCE_PP + 28, ++ MALI_CINSTR_PP_STALL_CYCLES_TRIANGLE_SETUP = MALI_CINSTR_COUNTER_SOURCE_PP + 29, ++ MALI_CINSTR_PP_QUAD_RASTERIZED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 30, ++ MALI_CINSTR_PP_FRAGMENT_RASTERIZED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 31, ++ MALI_CINSTR_PP_FRAGMENT_REJECTED_FRAGMENT_KILL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 32, ++ MALI_CINSTR_PP_FRAGMENT_REJECTED_FWD_FRAGMENT_KILL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 33, ++ MALI_CINSTR_PP_FRAGMENT_PASSED_ZSTENCIL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 34, ++ MALI_CINSTR_PP_PATCHES_REJECTED_EARLY_Z_STENCIL_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 35, ++ MALI_CINSTR_PP_PATCHES_EVALUATED = MALI_CINSTR_COUNTER_SOURCE_PP + 36, ++ MALI_CINSTR_PP_INSTRUCTION_COMPLETED_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 37, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_RENDEZVOUS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 38, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_VARYING_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 39, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_TEXTURE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 40, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_LOAD_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 41, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_TILE_READ_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 42, ++ MALI_CINSTR_PP_INSTRUCTION_FAILED_STORE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 43, ++ MALI_CINSTR_PP_RENDEZVOUS_BREAKAGE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 44, ++ MALI_CINSTR_PP_PIPELINE_BUBBLES_CYCLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 45, ++ MALI_CINSTR_PP_TEXTURE_MAPPER_MULTIPASS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 46, ++ MALI_CINSTR_PP_TEXTURE_MAPPER_CYCLE_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 47, ++ MALI_CINSTR_PP_VERTEX_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 48, ++ MALI_CINSTR_PP_VERTEX_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 49, ++ MALI_CINSTR_PP_VARYING_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 50, ++ MALI_CINSTR_PP_VARYING_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 51, ++ MALI_CINSTR_PP_VARYING_CACHE_CONFLICT_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 52, ++ MALI_CINSTR_PP_TEXTURE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 53, ++ MALI_CINSTR_PP_TEXTURE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 54, ++ MALI_CINSTR_PP_TEXTURE_CACHE_CONFLICT_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 55, ++ MALI_CINSTR_PP_PALETTE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 56, /* Mali 200 only */ ++ MALI_CINSTR_PP_PALETTE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 57, /* Mali 200 only */ ++ MALI_CINSTR_PP_COMPRESSED_TEXTURE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 56, /* Mali 400 class only */ ++ MALI_CINSTR_PP_COMPRESSED_TEXTURE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 57, /* Mali 400 class only */ ++ MALI_CINSTR_PP_LOAD_STORE_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 58, ++ MALI_CINSTR_PP_LOAD_STORE_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 59, ++ MALI_CINSTR_PP_PROGRAM_CACHE_HIT_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 60, ++ MALI_CINSTR_PP_PROGRAM_CACHE_MISS_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 61, ++ MALI_CINSTR_PP_JOB_COUNT = MALI_CINSTR_COUNTER_SOURCE_PP + 900, ++} cinstr_counters_m200_t; ++ ++#endif /*_MALI_UTGARD_COUNTERS_H_*/ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_ioctl.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_ioctl.h +new file mode 100644 +index 0000000..f0ea293 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_ioctl.h +@@ -0,0 +1,95 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_UTGARD_IOCTL_H__ ++#define __MALI_UTGARD_IOCTL_H__ ++ ++#include ++#include ++#include /* file system operations */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * @file mali_kernel_ioctl.h ++ * Interface to the Linux device driver. ++ * This file describes the interface needed to use the Linux device driver. ++ * Its interface is designed to used by the HAL implementation through a thin arch layer. ++ */ ++ ++/** ++ * ioctl commands ++ */ ++ ++#define MALI_IOC_BASE 0x82 ++#define MALI_IOC_CORE_BASE (_MALI_UK_CORE_SUBSYSTEM + MALI_IOC_BASE) ++#define MALI_IOC_MEMORY_BASE (_MALI_UK_MEMORY_SUBSYSTEM + MALI_IOC_BASE) ++#define MALI_IOC_PP_BASE (_MALI_UK_PP_SUBSYSTEM + MALI_IOC_BASE) ++#define MALI_IOC_GP_BASE (_MALI_UK_GP_SUBSYSTEM + MALI_IOC_BASE) ++#define MALI_IOC_PROFILING_BASE (_MALI_UK_PROFILING_SUBSYSTEM + MALI_IOC_BASE) ++#define MALI_IOC_VSYNC_BASE (_MALI_UK_VSYNC_SUBSYSTEM + MALI_IOC_BASE) ++ ++#define MALI_IOC_WAIT_FOR_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_WAIT_FOR_NOTIFICATION, _mali_uk_wait_for_notification_s *) ++#define MALI_IOC_GET_API_VERSION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_API_VERSION, _mali_uk_get_api_version_s *) ++#define MALI_IOC_POST_NOTIFICATION _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_POST_NOTIFICATION, _mali_uk_post_notification_s *) ++#define MALI_IOC_GET_USER_SETTING _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTING, _mali_uk_get_user_setting_s *) ++#define MALI_IOC_GET_USER_SETTINGS _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_GET_USER_SETTINGS, _mali_uk_get_user_settings_s *) ++#define MALI_IOC_REQUEST_HIGH_PRIORITY _IOW (MALI_IOC_CORE_BASE, _MALI_UK_REQUEST_HIGH_PRIORITY, _mali_uk_request_high_priority_s *) ++#define MALI_IOC_TIMELINE_GET_LATEST_POINT _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_TIMELINE_GET_LATEST_POINT, _mali_uk_timeline_get_latest_point_s *) ++#define MALI_IOC_TIMELINE_WAIT _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_TIMELINE_WAIT, _mali_uk_timeline_wait_s *) ++#define MALI_IOC_TIMELINE_CREATE_SYNC_FENCE _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_TIMELINE_CREATE_SYNC_FENCE, _mali_uk_timeline_create_sync_fence_s *) ++#define MALI_IOC_SOFT_JOB_START _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_SOFT_JOB_START, _mali_uk_soft_job_start_s *) ++#define MALI_IOC_SOFT_JOB_SIGNAL _IOWR(MALI_IOC_CORE_BASE, _MALI_UK_SOFT_JOB_SIGNAL, _mali_uk_soft_job_signal_s *) ++ ++#define MALI_IOC_MEM_MAP_EXT _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MAP_EXT_MEM, _mali_uk_map_external_mem_s *) ++#define MALI_IOC_MEM_UNMAP_EXT _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_UNMAP_EXT_MEM, _mali_uk_unmap_external_mem_s *) ++#define MALI_IOC_MEM_ATTACH_DMA_BUF _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_ATTACH_DMA_BUF, _mali_uk_attach_dma_buf_s *) ++#define MALI_IOC_MEM_RELEASE_DMA_BUF _IOW(MALI_IOC_MEMORY_BASE, _MALI_UK_RELEASE_DMA_BUF, _mali_uk_release_dma_buf_s *) ++#define MALI_IOC_MEM_DMA_BUF_GET_SIZE _IOR(MALI_IOC_MEMORY_BASE, _MALI_UK_DMA_BUF_GET_SIZE, _mali_uk_dma_buf_get_size_s *) ++#define MALI_IOC_MEM_ATTACH_UMP _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_ATTACH_UMP_MEM, _mali_uk_attach_ump_mem_s *) ++#define MALI_IOC_MEM_RELEASE_UMP _IOW(MALI_IOC_MEMORY_BASE, _MALI_UK_RELEASE_UMP_MEM, _mali_uk_release_ump_mem_s *) ++#define MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, _mali_uk_query_mmu_page_table_dump_size_s *) ++#define MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_DUMP_MMU_PAGE_TABLE, _mali_uk_dump_mmu_page_table_s *) ++#define MALI_IOC_MEM_WRITE_SAFE _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_MEM_WRITE_SAFE, _mali_uk_mem_write_safe_s *) ++ ++#define MALI_IOC_PP_START_JOB _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_START_JOB, _mali_uk_pp_start_job_s *) ++#define MALI_IOC_PP_AND_GP_START_JOB _IOWR(MALI_IOC_PP_BASE, _MALI_UK_PP_AND_GP_START_JOB, _mali_uk_pp_and_gp_start_job_s *) ++#define MALI_IOC_PP_NUMBER_OF_CORES_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_NUMBER_OF_CORES, _mali_uk_get_pp_number_of_cores_s *) ++#define MALI_IOC_PP_CORE_VERSION_GET _IOR (MALI_IOC_PP_BASE, _MALI_UK_GET_PP_CORE_VERSION, _mali_uk_get_pp_core_version_s * ) ++#define MALI_IOC_PP_DISABLE_WB _IOW (MALI_IOC_PP_BASE, _MALI_UK_PP_DISABLE_WB, _mali_uk_pp_disable_wb_s * ) ++ ++#define MALI_IOC_GP2_START_JOB _IOWR(MALI_IOC_GP_BASE, _MALI_UK_GP_START_JOB, _mali_uk_gp_start_job_s *) ++#define MALI_IOC_GP2_NUMBER_OF_CORES_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_NUMBER_OF_CORES, _mali_uk_get_gp_number_of_cores_s *) ++#define MALI_IOC_GP2_CORE_VERSION_GET _IOR (MALI_IOC_GP_BASE, _MALI_UK_GET_GP_CORE_VERSION, _mali_uk_get_gp_core_version_s *) ++#define MALI_IOC_GP2_SUSPEND_RESPONSE _IOW (MALI_IOC_GP_BASE, _MALI_UK_GP_SUSPEND_RESPONSE,_mali_uk_gp_suspend_response_s *) ++ ++#define MALI_IOC_PROFILING_START _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_START, _mali_uk_profiling_start_s *) ++#define MALI_IOC_PROFILING_ADD_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_ADD_EVENT, _mali_uk_profiling_add_event_s*) ++#define MALI_IOC_PROFILING_STOP _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_STOP, _mali_uk_profiling_stop_s *) ++#define MALI_IOC_PROFILING_GET_EVENT _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_EVENT, _mali_uk_profiling_get_event_s *) ++#define MALI_IOC_PROFILING_CLEAR _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_CLEAR, _mali_uk_profiling_clear_s *) ++#define MALI_IOC_PROFILING_GET_CONFIG _IOWR(MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_GET_CONFIG, _mali_uk_get_user_settings_s *) ++#define MALI_IOC_PROFILING_REPORT_SW_COUNTERS _IOW (MALI_IOC_PROFILING_BASE, _MALI_UK_PROFILING_REPORT_SW_COUNTERS, _mali_uk_sw_counters_report_s *) ++ ++#define MALI_IOC_VSYNC_EVENT_REPORT _IOW (MALI_IOC_VSYNC_BASE, _MALI_UK_VSYNC_EVENT_REPORT, _mali_uk_vsync_event_report_s *) ++ ++/* Deprecated ioctls */ ++#define MALI_IOC_MEM_GET_BIG_BLOCK _IOWR(MALI_IOC_MEMORY_BASE, _MALI_UK_GET_BIG_BLOCK, void *) ++#define MALI_IOC_MEM_FREE_BIG_BLOCK _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_FREE_BIG_BLOCK, void *) ++#define MALI_IOC_MEM_INIT _IOR (MALI_IOC_MEMORY_BASE, _MALI_UK_INIT_MEM, void *) ++#define MALI_IOC_MEM_TERM _IOW (MALI_IOC_MEMORY_BASE, _MALI_UK_TERM_MEM, void *) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UTGARD_IOCTL_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_events.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_events.h +new file mode 100644 +index 0000000..5cdd8ee +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_events.h +@@ -0,0 +1,174 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef _MALI_UTGARD_PROFILING_EVENTS_H_ ++#define _MALI_UTGARD_PROFILING_EVENTS_H_ ++ ++/* ++ * The event ID is a 32 bit value consisting of different fields ++ * reserved, 4 bits, for future use ++ * event type, 4 bits, cinstr_profiling_event_type_t ++ * event channel, 8 bits, the source of the event. ++ * event data, 16 bit field, data depending on event type ++ */ ++ ++/** ++ * Specifies what kind of event this is ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_TYPE_SINGLE = 0 << 24, ++ MALI_PROFILING_EVENT_TYPE_START = 1 << 24, ++ MALI_PROFILING_EVENT_TYPE_STOP = 2 << 24, ++ MALI_PROFILING_EVENT_TYPE_SUSPEND = 3 << 24, ++ MALI_PROFILING_EVENT_TYPE_RESUME = 4 << 24, ++} cinstr_profiling_event_type_t; ++ ++ ++/** ++ * Secifies the channel/source of the event ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_CHANNEL_SOFTWARE = 0 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_GP0 = 1 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP0 = 5 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP1 = 6 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP2 = 7 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP3 = 8 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP4 = 9 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP5 = 10 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP6 = 11 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_PP7 = 12 << 16, ++ MALI_PROFILING_EVENT_CHANNEL_GPU = 21 << 16, ++} cinstr_profiling_event_channel_t; ++ ++ ++#define MALI_PROFILING_MAKE_EVENT_CHANNEL_GP(num) (((MALI_PROFILING_EVENT_CHANNEL_GP0 >> 16) + (num)) << 16) ++#define MALI_PROFILING_MAKE_EVENT_CHANNEL_PP(num) (((MALI_PROFILING_EVENT_CHANNEL_PP0 >> 16) + (num)) << 16) ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from software channel ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_NONE = 0, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_NEW_FRAME = 1, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_FLUSH = 2, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_SWAP_BUFFERS = 3, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_FB_EVENT = 4, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_GP_ENQUEUE = 5, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_PP_ENQUEUE = 6, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_READBACK = 7, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_WRITEBACK = 8, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_ENTER_API_FUNC = 10, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC = 11, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_DISCARD_ATTACHMENTS = 13, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_TRY_LOCK = 53, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_LOCK = 54, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_UMP_UNLOCK = 55, ++ MALI_PROFILING_EVENT_REASON_SINGLE_LOCK_CONTENDED = 56, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_MALI_FENCE_DUP = 57, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_SET_PP_JOB_FENCE = 58, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_WAIT_SYNC = 59, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_CREATE_FENCE_SYNC = 60, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_CREATE_NATIVE_FENCE_SYNC = 61, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_FENCE_FLUSH = 62, ++ MALI_PROFILING_EVENT_REASON_SINGLE_SW_EGL_FLUSH_SERVER_WAITS= 63, ++} cinstr_profiling_event_reason_single_sw_t; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_START/STOP is used from software channel ++ * to inform whether the core is physical or virtual ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_PHYSICAL = 0, ++ MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL = 1, ++} cinstr_profiling_event_reason_start_stop_hw_t; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_START/STOP is used from software channel ++ */ ++typedef enum { ++ /*MALI_PROFILING_EVENT_REASON_START_STOP_SW_NONE = 0,*/ ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_MALI = 1, ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_CALLBACK_THREAD = 2, ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_WORKER_THREAD = 3, ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_BOTTOM_HALF = 4, ++ MALI_PROFILING_EVENT_REASON_START_STOP_SW_UPPER_HALF = 5, ++} cinstr_profiling_event_reason_start_stop_sw_t; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SUSPEND/RESUME is used from software channel ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_NONE = 0, /* used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_PIPELINE_FULL = 1, /* NOT used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VSYNC = 26, /* used in some build configurations */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_FB_IFRAME_WAIT = 27, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_FB_IFRAME_SYNC = 28, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VG_WAIT_FILTER_CLEANUP = 29, /* used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_VG_WAIT_TEXTURE = 30, /* used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_GLES_WAIT_MIPLEVEL = 31, /* used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_GLES_WAIT_READPIXELS = 32, /* used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_WAIT_SWAP_IMMEDIATE = 33, /* NOT used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_ICS_QUEUE_BUFFER = 34, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_ICS_DEQUEUE_BUFFER = 35, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_UMP_LOCK = 36, /* Not currently used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_X11_GLOBAL_LOCK = 37, /* Not currently used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_X11_SWAP = 38, /* Not currently used */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_MALI_EGL_IMAGE_SYNC_WAIT = 39, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_GP_JOB_HANDLING = 40, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_PP_JOB_HANDLING = 41, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_MALI_FENCE_MERGE = 42, /* USED */ ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_MALI_FENCE_DUP = 43, ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_FLUSH_SERVER_WAITS = 44, ++ MALI_PROFILING_EVENT_REASON_SUSPEND_RESUME_SW_EGL_WAIT_SYNC = 45, /* USED */ ++} cinstr_profiling_event_reason_suspend_resume_sw_t; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from a HW channel (GPx+PPx) ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_NONE = 0, ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_INTERRUPT = 1, ++ MALI_PROFILING_EVENT_REASON_SINGLE_HW_FLUSH = 2, ++} cinstr_profiling_event_reason_single_hw_t; ++ ++/** ++ * These events are applicable when the type MALI_PROFILING_EVENT_TYPE_SINGLE is used from the GPU channel ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_NONE = 0, ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_FREQ_VOLT_CHANGE = 1, ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L20_COUNTERS = 2, ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L21_COUNTERS = 3, ++ MALI_PROFILING_EVENT_REASON_SINGLE_GPU_L22_COUNTERS = 4, ++} cinstr_profiling_event_reason_single_gpu_t; ++ ++/** ++ * These values are applicable for the 3rd data parameter when ++ * the type MALI_PROFILING_EVENT_TYPE_START is used from the software channel ++ * with the MALI_PROFILING_EVENT_REASON_START_STOP_BOTTOM_HALF reason. ++ */ ++typedef enum { ++ MALI_PROFILING_EVENT_DATA_CORE_GP0 = 1, ++ MALI_PROFILING_EVENT_DATA_CORE_PP0 = 5, ++ MALI_PROFILING_EVENT_DATA_CORE_PP1 = 6, ++ MALI_PROFILING_EVENT_DATA_CORE_PP2 = 7, ++ MALI_PROFILING_EVENT_DATA_CORE_PP3 = 8, ++ MALI_PROFILING_EVENT_DATA_CORE_PP4 = 9, ++ MALI_PROFILING_EVENT_DATA_CORE_PP5 = 10, ++ MALI_PROFILING_EVENT_DATA_CORE_PP6 = 11, ++ MALI_PROFILING_EVENT_DATA_CORE_PP7 = 12, ++} cinstr_profiling_event_data_core_t; ++ ++#define MALI_PROFILING_MAKE_EVENT_DATA_CORE_GP(num) (MALI_PROFILING_EVENT_DATA_CORE_GP0 + (num)) ++#define MALI_PROFILING_MAKE_EVENT_DATA_CORE_PP(num) (MALI_PROFILING_EVENT_DATA_CORE_PP0 + (num)) ++ ++ ++#endif /*_MALI_UTGARD_PROFILING_EVENTS_H_*/ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_gator_api.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_gator_api.h +new file mode 100644 +index 0000000..f8af3e4 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_profiling_gator_api.h +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_UTGARD_PROFILING_GATOR_API_H__ ++#define __MALI_UTGARD_PROFILING_GATOR_API_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define MALI_PROFILING_API_VERSION 4 ++ ++#define MAX_NUM_L2_CACHE_CORES 3 ++#define MAX_NUM_FP_CORES 8 ++#define MAX_NUM_VP_CORES 1 ++ ++/** The list of events supported by the Mali DDK. */ ++typedef enum { ++ /* Vertex processor activity */ ++ ACTIVITY_VP_0 = 0, ++ ++ /* Fragment processor activity */ ++ ACTIVITY_FP_0, ++ ACTIVITY_FP_1, ++ ACTIVITY_FP_2, ++ ACTIVITY_FP_3, ++ ACTIVITY_FP_4, ++ ACTIVITY_FP_5, ++ ACTIVITY_FP_6, ++ ACTIVITY_FP_7, ++ ++ /* L2 cache counters */ ++ COUNTER_L2_0_C0, ++ COUNTER_L2_0_C1, ++ COUNTER_L2_1_C0, ++ COUNTER_L2_1_C1, ++ COUNTER_L2_2_C0, ++ COUNTER_L2_2_C1, ++ ++ /* Vertex processor counters */ ++ COUNTER_VP_0_C0, ++ COUNTER_VP_0_C1, ++ ++ /* Fragment processor counters */ ++ COUNTER_FP_0_C0, ++ COUNTER_FP_0_C1, ++ COUNTER_FP_1_C0, ++ COUNTER_FP_1_C1, ++ COUNTER_FP_2_C0, ++ COUNTER_FP_2_C1, ++ COUNTER_FP_3_C0, ++ COUNTER_FP_3_C1, ++ COUNTER_FP_4_C0, ++ COUNTER_FP_4_C1, ++ COUNTER_FP_5_C0, ++ COUNTER_FP_5_C1, ++ COUNTER_FP_6_C0, ++ COUNTER_FP_6_C1, ++ COUNTER_FP_7_C0, ++ COUNTER_FP_7_C1, ++ ++ /* ++ * If more hardware counters are added, the _mali_osk_hw_counter_table ++ * below should also be updated. ++ */ ++ ++ /* EGL software counters */ ++ COUNTER_EGL_BLIT_TIME, ++ ++ /* GLES software counters */ ++ COUNTER_GLES_DRAW_ELEMENTS_CALLS, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_INDICES, ++ COUNTER_GLES_DRAW_ELEMENTS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_ARRAYS_CALLS, ++ COUNTER_GLES_DRAW_ARRAYS_NUM_TRANSFORMED, ++ COUNTER_GLES_DRAW_POINTS, ++ COUNTER_GLES_DRAW_LINES, ++ COUNTER_GLES_DRAW_LINE_LOOP, ++ COUNTER_GLES_DRAW_LINE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLES, ++ COUNTER_GLES_DRAW_TRIANGLE_STRIP, ++ COUNTER_GLES_DRAW_TRIANGLE_FAN, ++ COUNTER_GLES_NON_VBO_DATA_COPY_TIME, ++ COUNTER_GLES_UNIFORM_BYTES_COPIED_TO_MALI, ++ COUNTER_GLES_UPLOAD_TEXTURE_TIME, ++ COUNTER_GLES_UPLOAD_VBO_TIME, ++ COUNTER_GLES_NUM_FLUSHES, ++ COUNTER_GLES_NUM_VSHADERS_GENERATED, ++ COUNTER_GLES_NUM_FSHADERS_GENERATED, ++ COUNTER_GLES_VSHADER_GEN_TIME, ++ COUNTER_GLES_FSHADER_GEN_TIME, ++ COUNTER_GLES_INPUT_TRIANGLES, ++ COUNTER_GLES_VXCACHE_HIT, ++ COUNTER_GLES_VXCACHE_MISS, ++ COUNTER_GLES_VXCACHE_COLLISION, ++ COUNTER_GLES_CULLED_TRIANGLES, ++ COUNTER_GLES_CULLED_LINES, ++ COUNTER_GLES_BACKFACE_TRIANGLES, ++ COUNTER_GLES_GBCLIP_TRIANGLES, ++ COUNTER_GLES_GBCLIP_LINES, ++ COUNTER_GLES_TRIANGLES_DRAWN, ++ COUNTER_GLES_DRAWCALL_TIME, ++ COUNTER_GLES_TRIANGLES_COUNT, ++ COUNTER_GLES_INDEPENDENT_TRIANGLES_COUNT, ++ COUNTER_GLES_STRIP_TRIANGLES_COUNT, ++ COUNTER_GLES_FAN_TRIANGLES_COUNT, ++ COUNTER_GLES_LINES_COUNT, ++ COUNTER_GLES_INDEPENDENT_LINES_COUNT, ++ COUNTER_GLES_STRIP_LINES_COUNT, ++ COUNTER_GLES_LOOP_LINES_COUNT, ++ ++ /* Framebuffer capture pseudo-counter */ ++ COUNTER_FILMSTRIP, ++ ++ NUMBER_OF_EVENTS ++} _mali_osk_counter_id; ++ ++#define FIRST_ACTIVITY_EVENT ACTIVITY_VP_0 ++#define LAST_ACTIVITY_EVENT ACTIVITY_FP_7 ++ ++#define FIRST_HW_COUNTER COUNTER_L2_0_C0 ++#define LAST_HW_COUNTER COUNTER_FP_7_C1 ++ ++#define FIRST_SW_COUNTER COUNTER_EGL_BLIT_TIME ++#define LAST_SW_COUNTER COUNTER_GLES_LOOP_LINES_COUNT ++ ++#define FIRST_SPECIAL_COUNTER COUNTER_FILMSTRIP ++#define LAST_SPECIAL_COUNTER COUNTER_FILMSTRIP ++ ++/** ++ * Structure to pass performance counter data of a Mali core ++ */ ++typedef struct _mali_profiling_core_counters { ++ u32 source0; ++ u32 value0; ++ u32 source1; ++ u32 value1; ++} _mali_profiling_core_counters; ++ ++/** ++ * Structure to pass performance counter data of Mali L2 cache cores ++ */ ++typedef struct _mali_profiling_l2_counter_values { ++ struct _mali_profiling_core_counters cores[MAX_NUM_L2_CACHE_CORES]; ++} _mali_profiling_l2_counter_values; ++ ++/** ++ * Structure to pass data defining Mali instance in use: ++ * ++ * mali_product_id - Mali product id ++ * mali_version_major - Mali version major number ++ * mali_version_minor - Mali version minor number ++ * num_of_l2_cores - number of L2 cache cores ++ * num_of_fp_cores - number of fragment processor cores ++ * num_of_vp_cores - number of vertex processor cores ++ */ ++typedef struct _mali_profiling_mali_version { ++ u32 mali_product_id; ++ u32 mali_version_major; ++ u32 mali_version_minor; ++ u32 num_of_l2_cores; ++ u32 num_of_fp_cores; ++ u32 num_of_vp_cores; ++} _mali_profiling_mali_version; ++ ++/* ++ * List of possible actions to be controlled by Streamline. ++ * The following numbers are used by gator to control the frame buffer dumping and s/w counter reporting. ++ * We cannot use the enums in mali_uk_types.h because they are unknown inside gator. ++ */ ++#define FBDUMP_CONTROL_ENABLE (1) ++#define FBDUMP_CONTROL_RATE (2) ++#define SW_COUNTER_ENABLE (3) ++#define FBDUMP_CONTROL_RESIZE_FACTOR (4) ++ ++void _mali_profiling_control(u32 action, u32 value); ++ ++u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values); ++ ++int _mali_profiling_set_event(u32 counter_id, s32 event_id); ++ ++u32 _mali_profiling_get_api_version(void); ++ ++void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UTGARD_PROFILING_GATOR_API_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_uk_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_uk_types.h +new file mode 100644 +index 0000000..d032f9d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/include/linux/mali/mali_utgard_uk_types.h +@@ -0,0 +1,1132 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_uk_types.h ++ * Defines the types and constants used in the user-kernel interface ++ */ ++ ++#ifndef __MALI_UTGARD_UK_TYPES_H__ ++#define __MALI_UTGARD_UK_TYPES_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Iteration functions depend on these values being consecutive. */ ++#define MALI_UK_TIMELINE_GP 0 ++#define MALI_UK_TIMELINE_PP 1 ++#define MALI_UK_TIMELINE_SOFT 2 ++#define MALI_UK_TIMELINE_MAX 3 ++ ++typedef struct { ++ u32 points[MALI_UK_TIMELINE_MAX]; ++ s32 sync_fd; ++} _mali_uk_fence_t; ++ ++/** ++ * @addtogroup uddapi Unified Device Driver (UDD) APIs ++ * ++ * @{ ++ */ ++ ++/** ++ * @addtogroup u_k_api UDD User/Kernel Interface (U/K) APIs ++ * ++ * @{ ++ */ ++ ++/** @defgroup _mali_uk_core U/K Core ++ * @{ */ ++ ++/** Definition of subsystem numbers, to assist in creating a unique identifier ++ * for each U/K call. ++ * ++ * @see _mali_uk_functions */ ++typedef enum { ++ _MALI_UK_CORE_SUBSYSTEM, /**< Core Group of U/K calls */ ++ _MALI_UK_MEMORY_SUBSYSTEM, /**< Memory Group of U/K calls */ ++ _MALI_UK_PP_SUBSYSTEM, /**< Fragment Processor Group of U/K calls */ ++ _MALI_UK_GP_SUBSYSTEM, /**< Vertex Processor Group of U/K calls */ ++ _MALI_UK_PROFILING_SUBSYSTEM, /**< Profiling Group of U/K calls */ ++ _MALI_UK_PMM_SUBSYSTEM, /**< Power Management Module Group of U/K calls */ ++ _MALI_UK_VSYNC_SUBSYSTEM, /**< VSYNC Group of U/K calls */ ++} _mali_uk_subsystem_t; ++ ++/** Within a function group each function has its unique sequence number ++ * to assist in creating a unique identifier for each U/K call. ++ * ++ * An ordered pair of numbers selected from ++ * ( \ref _mali_uk_subsystem_t,\ref _mali_uk_functions) will uniquely identify the ++ * U/K call across all groups of functions, and all functions. */ ++typedef enum { ++ /** Core functions */ ++ ++ _MALI_UK_OPEN = 0, /**< _mali_ukk_open() */ ++ _MALI_UK_CLOSE, /**< _mali_ukk_close() */ ++ _MALI_UK_WAIT_FOR_NOTIFICATION, /**< _mali_ukk_wait_for_notification() */ ++ _MALI_UK_GET_API_VERSION, /**< _mali_ukk_get_api_version() */ ++ _MALI_UK_POST_NOTIFICATION, /**< _mali_ukk_post_notification() */ ++ _MALI_UK_GET_USER_SETTING, /**< _mali_ukk_get_user_setting() *//**< [out] */ ++ _MALI_UK_GET_USER_SETTINGS, /**< _mali_ukk_get_user_settings() *//**< [out] */ ++ _MALI_UK_REQUEST_HIGH_PRIORITY, /**< _mali_ukk_request_high_priority() */ ++ _MALI_UK_TIMELINE_GET_LATEST_POINT, /**< _mali_ukk_timeline_get_latest_point() */ ++ _MALI_UK_TIMELINE_WAIT, /**< _mali_ukk_timeline_wait() */ ++ _MALI_UK_TIMELINE_CREATE_SYNC_FENCE, /**< _mali_ukk_timeline_create_sync_fence() */ ++ _MALI_UK_SOFT_JOB_START, /**< _mali_ukk_soft_job_start() */ ++ _MALI_UK_SOFT_JOB_SIGNAL, /**< _mali_ukk_soft_job_signal() */ ++ ++ /** Memory functions */ ++ ++ _MALI_UK_INIT_MEM = 0, /**< _mali_ukk_init_mem() */ ++ _MALI_UK_TERM_MEM, /**< _mali_ukk_term_mem() */ ++ _MALI_UK_GET_BIG_BLOCK, /**< _mali_ukk_get_big_block() */ ++ _MALI_UK_FREE_BIG_BLOCK, /**< _mali_ukk_free_big_block() */ ++ _MALI_UK_MAP_MEM, /**< _mali_ukk_mem_mmap() */ ++ _MALI_UK_UNMAP_MEM, /**< _mali_ukk_mem_munmap() */ ++ _MALI_UK_QUERY_MMU_PAGE_TABLE_DUMP_SIZE, /**< _mali_ukk_mem_get_mmu_page_table_dump_size() */ ++ _MALI_UK_DUMP_MMU_PAGE_TABLE, /**< _mali_ukk_mem_dump_mmu_page_table() */ ++ _MALI_UK_ATTACH_DMA_BUF, /**< _mali_ukk_attach_dma_buf() */ ++ _MALI_UK_RELEASE_DMA_BUF, /**< _mali_ukk_release_dma_buf() */ ++ _MALI_UK_DMA_BUF_GET_SIZE, /**< _mali_ukk_dma_buf_get_size() */ ++ _MALI_UK_ATTACH_UMP_MEM, /**< _mali_ukk_attach_ump_mem() */ ++ _MALI_UK_RELEASE_UMP_MEM, /**< _mali_ukk_release_ump_mem() */ ++ _MALI_UK_MAP_EXT_MEM, /**< _mali_uku_map_external_mem() */ ++ _MALI_UK_UNMAP_EXT_MEM, /**< _mali_uku_unmap_external_mem() */ ++ _MALI_UK_VA_TO_MALI_PA, /**< _mali_uku_va_to_mali_pa() */ ++ _MALI_UK_MEM_WRITE_SAFE, /**< _mali_uku_mem_write_safe() */ ++ ++ /** Common functions for each core */ ++ ++ _MALI_UK_START_JOB = 0, /**< Start a Fragment/Vertex Processor Job on a core */ ++ _MALI_UK_GET_NUMBER_OF_CORES, /**< Get the number of Fragment/Vertex Processor cores */ ++ _MALI_UK_GET_CORE_VERSION, /**< Get the Fragment/Vertex Processor version compatible with all cores */ ++ ++ /** Fragment Processor Functions */ ++ ++ _MALI_UK_PP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_pp_start_job() */ ++ _MALI_UK_GET_PP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_pp_number_of_cores() */ ++ _MALI_UK_GET_PP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_pp_core_version() */ ++ _MALI_UK_PP_DISABLE_WB, /**< _mali_ukk_pp_job_disable_wb() */ ++ _MALI_UK_PP_AND_GP_START_JOB, /**< _mali_ukk_pp_and_gp_start_job() */ ++ ++ /** Vertex Processor Functions */ ++ ++ _MALI_UK_GP_START_JOB = _MALI_UK_START_JOB, /**< _mali_ukk_gp_start_job() */ ++ _MALI_UK_GET_GP_NUMBER_OF_CORES = _MALI_UK_GET_NUMBER_OF_CORES, /**< _mali_ukk_get_gp_number_of_cores() */ ++ _MALI_UK_GET_GP_CORE_VERSION = _MALI_UK_GET_CORE_VERSION, /**< _mali_ukk_get_gp_core_version() */ ++ _MALI_UK_GP_SUSPEND_RESPONSE, /**< _mali_ukk_gp_suspend_response() */ ++ ++ /** Profiling functions */ ++ ++ _MALI_UK_PROFILING_START = 0, /**< __mali_uku_profiling_start() */ ++ _MALI_UK_PROFILING_ADD_EVENT, /**< __mali_uku_profiling_add_event() */ ++ _MALI_UK_PROFILING_STOP, /**< __mali_uku_profiling_stop() */ ++ _MALI_UK_PROFILING_GET_EVENT, /**< __mali_uku_profiling_get_event() */ ++ _MALI_UK_PROFILING_CLEAR, /**< __mali_uku_profiling_clear() */ ++ _MALI_UK_PROFILING_GET_CONFIG, /**< __mali_uku_profiling_get_config() */ ++ _MALI_UK_PROFILING_REPORT_SW_COUNTERS,/**< __mali_uku_profiling_report_sw_counters() */ ++ ++ /** VSYNC reporting fuctions */ ++ _MALI_UK_VSYNC_EVENT_REPORT = 0, /**< _mali_ukk_vsync_event_report() */ ++ ++} _mali_uk_functions; ++ ++/** @brief Get the size necessary for system info ++ * ++ * @see _mali_ukk_get_system_info_size() ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 size; /**< [out] size of buffer necessary to hold system information data, in bytes */ ++} _mali_uk_get_system_info_size_s; ++ ++ ++/** @defgroup _mali_uk_getsysteminfo U/K Get System Info ++ * @{ */ ++ ++/** ++ * Type definition for the core version number. ++ * Used when returning the version number read from a core ++ * ++ * Its format is that of the 32-bit Version register for a particular core. ++ * Refer to the "Mali200 and MaliGP2 3D Graphics Processor Technical Reference ++ * Manual", ARM DDI 0415C, for more information. ++ */ ++typedef u32 _mali_core_version; ++ ++/** ++ * Enum values for the different modes the driver can be put in. ++ * Normal is the default mode. The driver then uses a job queue and takes job objects from the clients. ++ * Job completion is reported using the _mali_ukk_wait_for_notification call. ++ * The driver blocks this io command until a job has completed or failed or a timeout occurs. ++ * ++ * The 'raw' mode is reserved for future expansion. ++ */ ++typedef enum _mali_driver_mode { ++ _MALI_DRIVER_MODE_RAW = 1, /**< Reserved for future expansion */ ++ _MALI_DRIVER_MODE_NORMAL = 2 /**< Normal mode of operation */ ++} _mali_driver_mode; ++ ++/** @brief List of possible cores ++ * ++ * add new entries to the end of this enum */ ++typedef enum _mali_core_type { ++ _MALI_GP2 = 2, /**< MaliGP2 Programmable Vertex Processor */ ++ _MALI_200 = 5, /**< Mali200 Programmable Fragment Processor */ ++ _MALI_400_GP = 6, /**< Mali400 Programmable Vertex Processor */ ++ _MALI_400_PP = 7, /**< Mali400 Programmable Fragment Processor */ ++ /* insert new core here, do NOT alter the existing values */ ++} _mali_core_type; ++ ++ ++/** @brief Capabilities of Memory Banks ++ * ++ * These may be used to restrict memory banks for certain uses. They may be ++ * used when access is not possible (e.g. Bus does not support access to it) ++ * or when access is possible but not desired (e.g. Access is slow). ++ * ++ * In the case of 'possible but not desired', there is no way of specifying ++ * the flags as an optimization hint, so that the memory could be used as a ++ * last resort. ++ * ++ * @see _mali_mem_info ++ */ ++typedef enum _mali_bus_usage { ++ ++ _MALI_PP_READABLE = (1<<0), /** Readable by the Fragment Processor */ ++ _MALI_PP_WRITEABLE = (1<<1), /** Writeable by the Fragment Processor */ ++ _MALI_GP_READABLE = (1<<2), /** Readable by the Vertex Processor */ ++ _MALI_GP_WRITEABLE = (1<<3), /** Writeable by the Vertex Processor */ ++ _MALI_CPU_READABLE = (1<<4), /** Readable by the CPU */ ++ _MALI_CPU_WRITEABLE = (1<<5), /** Writeable by the CPU */ ++ _MALI_GP_L2_ALLOC = (1<<6), /** GP allocate mali L2 cache lines*/ ++ _MALI_MMU_READABLE = _MALI_PP_READABLE | _MALI_GP_READABLE, /** Readable by the MMU (including all cores behind it) */ ++ _MALI_MMU_WRITEABLE = _MALI_PP_WRITEABLE | _MALI_GP_WRITEABLE, /** Writeable by the MMU (including all cores behind it) */ ++} _mali_bus_usage; ++ ++typedef enum mali_memory_cache_settings { ++ MALI_CACHE_STANDARD = 0, ++ MALI_CACHE_GP_READ_ALLOCATE = 1, ++} mali_memory_cache_settings ; ++ ++ ++/** @brief Information about the Mali Memory system ++ * ++ * Information is stored in a linked list, which is stored entirely in the ++ * buffer pointed to by the system_info member of the ++ * _mali_uk_get_system_info_s arguments provided to _mali_ukk_get_system_info() ++ * ++ * Each element of the linked list describes a single Mali Memory bank. ++ * Each allocation can only come from one bank, and will not cross multiple ++ * banks. ++ * ++ * On Mali-MMU systems, there is only one bank, which describes the maximum ++ * possible address range that could be allocated (which may be much less than ++ * the available physical memory) ++ * ++ * The flags member describes the capabilities of the memory. It is an error ++ * to attempt to build a job for a particular core (PP or GP) when the memory ++ * regions used do not have the capabilities for supporting that core. This ++ * would result in a job abort from the Device Driver. ++ * ++ * For example, it is correct to build a PP job where read-only data structures ++ * are taken from a memory with _MALI_PP_READABLE set and ++ * _MALI_PP_WRITEABLE clear, and a framebuffer with _MALI_PP_WRITEABLE set and ++ * _MALI_PP_READABLE clear. However, it would be incorrect to use a framebuffer ++ * where _MALI_PP_WRITEABLE is clear. ++ */ ++typedef struct _mali_mem_info { ++ u32 size; /**< Size of the memory bank in bytes */ ++ _mali_bus_usage flags; /**< Capabilitiy flags of the memory */ ++ u32 maximum_order_supported; /**< log2 supported size */ ++ u32 identifier; /* mali_memory_cache_settings cache_settings; */ ++ struct _mali_mem_info * next; /**< Next List Link */ ++} _mali_mem_info; ++ ++/** @} */ /* end group _mali_uk_core */ ++ ++ ++/** @defgroup _mali_uk_gp U/K Vertex Processor ++ * @{ */ ++ ++/** @defgroup _mali_uk_gp_suspend_response_s Vertex Processor Suspend Response ++ * @{ */ ++ ++/** @brief Arguments for _mali_ukk_gp_suspend_response() ++ * ++ * When _mali_wait_for_notification() receives notification that a ++ * Vertex Processor job was suspended, you need to send a response to indicate ++ * what needs to happen with this job. You can either abort or resume the job. ++ * ++ * - set @c code to indicate response code. This is either @c _MALIGP_JOB_ABORT or ++ * @c _MALIGP_JOB_RESUME_WITH_NEW_HEAP to indicate you will provide a new heap ++ * for the job that will resolve the out of memory condition for the job. ++ * - copy the @c cookie value from the @c _mali_uk_gp_job_suspended_s notification; ++ * this is an identifier for the suspended job ++ * - set @c arguments[0] and @c arguments[1] to zero if you abort the job. If ++ * you resume it, @c argument[0] should specify the Mali start address for the new ++ * heap and @c argument[1] the Mali end address of the heap. ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * ++ */ ++typedef enum _maligp_job_suspended_response_code { ++ _MALIGP_JOB_ABORT, /**< Abort the Vertex Processor job */ ++ _MALIGP_JOB_RESUME_WITH_NEW_HEAP /**< Resume the Vertex Processor job with a new heap */ ++} _maligp_job_suspended_response_code; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 cookie; /**< [in] cookie from the _mali_uk_gp_job_suspended_s notification */ ++ _maligp_job_suspended_response_code code; /**< [in] abort or resume response code, see \ref _maligp_job_suspended_response_code */ ++ u32 arguments[2]; /**< [in] 0 when aborting a job. When resuming a job, the Mali start and end address for a new heap to resume the job with */ ++} _mali_uk_gp_suspend_response_s; ++ ++/** @} */ /* end group _mali_uk_gp_suspend_response_s */ ++ ++/** @defgroup _mali_uk_gpstartjob_s Vertex Processor Start Job ++ * @{ */ ++ ++/** @brief Status indicating the result of starting a Vertex or Fragment processor job */ ++typedef enum { ++ _MALI_UK_START_JOB_STARTED, /**< Job started */ ++ _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE /**< Job could not be started at this time. Try starting the job again */ ++} _mali_uk_start_job_status; ++ ++/** @brief Status indicating the result of the execution of a Vertex or Fragment processor job */ ++ ++typedef enum { ++ _MALI_UK_JOB_STATUS_END_SUCCESS = 1<<(16+0), ++ _MALI_UK_JOB_STATUS_END_OOM = 1<<(16+1), ++ _MALI_UK_JOB_STATUS_END_ABORT = 1<<(16+2), ++ _MALI_UK_JOB_STATUS_END_TIMEOUT_SW = 1<<(16+3), ++ _MALI_UK_JOB_STATUS_END_HANG = 1<<(16+4), ++ _MALI_UK_JOB_STATUS_END_SEG_FAULT = 1<<(16+5), ++ _MALI_UK_JOB_STATUS_END_ILLEGAL_JOB = 1<<(16+6), ++ _MALI_UK_JOB_STATUS_END_UNKNOWN_ERR = 1<<(16+7), ++ _MALI_UK_JOB_STATUS_END_SHUTDOWN = 1<<(16+8), ++ _MALI_UK_JOB_STATUS_END_SYSTEM_UNUSABLE = 1<<(16+9) ++} _mali_uk_job_status; ++ ++#define MALIGP2_NUM_REGS_FRAME (6) ++ ++/** @brief Arguments for _mali_ukk_gp_start_job() ++ * ++ * To start a Vertex Processor job ++ * - associate the request with a reference to a @c mali_gp_job_info by setting ++ * user_job_ptr to the address of the @c mali_gp_job_info of the job. ++ * - set @c priority to the priority of the @c mali_gp_job_info ++ * - specify a timeout for the job by setting @c watchdog_msecs to the number of ++ * milliseconds the job is allowed to run. Specifying a value of 0 selects the ++ * default timeout in use by the device driver. ++ * - copy the frame registers from the @c mali_gp_job_info into @c frame_registers. ++ * - set the @c perf_counter_flag, @c perf_counter_src0 and @c perf_counter_src1 to zero ++ * for a non-instrumented build. For an instrumented build you can use up ++ * to two performance counters. Set the corresponding bit in @c perf_counter_flag ++ * to enable them. @c perf_counter_src0 and @c perf_counter_src1 specify ++ * the source of what needs to get counted (e.g. number of vertex loader ++ * cache hits). For source id values, see ARM DDI0415A, Table 3-60. ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * ++ * When @c _mali_ukk_gp_start_job() returns @c _MALI_OSK_ERR_OK, status contains the ++ * result of the request (see \ref _mali_uk_start_job_status). If the job could ++ * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be ++ * tried again. ++ * ++ * After the job has started, @c _mali_wait_for_notification() will be notified ++ * that the job finished or got suspended. It may get suspended due to ++ * resource shortage. If it finished (see _mali_ukk_wait_for_notification()) ++ * the notification will contain a @c _mali_uk_gp_job_finished_s result. If ++ * it got suspended the notification will contain a @c _mali_uk_gp_job_suspended_s ++ * result. ++ * ++ * The @c _mali_uk_gp_job_finished_s contains the job status (see \ref _mali_uk_job_status), ++ * the number of milliseconds the job took to render, and values of core registers ++ * when the job finished (irq status, performance counters, renderer list ++ * address). A job has finished succesfully when its status is ++ * @c _MALI_UK_JOB_STATUS_FINISHED. If the hardware detected a timeout while rendering ++ * the job, or software detected the job is taking more than watchdog_msecs to ++ * complete, the status will indicate @c _MALI_UK_JOB_STATUS_HANG. ++ * If the hardware detected a bus error while accessing memory associated with the ++ * job, status will indicate @c _MALI_UK_JOB_STATUS_SEG_FAULT. ++ * status will indicate @c _MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to ++ * stop the job but the job didn't start on the hardware yet, e.g. when the ++ * driver shutdown. ++ * ++ * In case the job got suspended, @c _mali_uk_gp_job_suspended_s contains ++ * the @c user_job_ptr identifier used to start the job with, the @c reason ++ * why the job stalled (see \ref _maligp_job_suspended_reason) and a @c cookie ++ * to identify the core on which the job stalled. This @c cookie will be needed ++ * when responding to this nofication by means of _mali_ukk_gp_suspend_response(). ++ * (see _mali_ukk_gp_suspend_response()). The response is either to abort or ++ * resume the job. If the job got suspended due to an out of memory condition ++ * you may be able to resolve this by providing more memory and resuming the job. ++ * ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 user_job_ptr; /**< [in] identifier for the job in user space, a @c mali_gp_job_info* */ ++ u32 priority; /**< [in] job priority. A lower number means higher priority */ ++ u32 frame_registers[MALIGP2_NUM_REGS_FRAME]; /**< [in] core specific registers associated with this job */ ++ u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ ++ u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ ++ u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ ++ u32 frame_builder_id; /**< [in] id of the originating frame builder */ ++ u32 flush_id; /**< [in] flush id within the originating frame builder */ ++ _mali_uk_fence_t fence; /**< [in] fence this job must wait on */ ++ u32 *timeline_point_ptr; /**< [in,out] pointer to location where point on gp timeline for this job will be written */ ++} _mali_uk_gp_start_job_s; ++ ++#define _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE (1<<0) /**< Enable performance counter SRC0 for a job */ ++#define _MALI_PERFORMANCE_COUNTER_FLAG_SRC1_ENABLE (1<<1) /**< Enable performance counter SRC1 for a job */ ++#define _MALI_PERFORMANCE_COUNTER_FLAG_HEATMAP_ENABLE (1<<2) /**< Enable per tile (aka heatmap) generation with for a job (using the enabled counter sources) */ ++ ++/** @} */ /* end group _mali_uk_gpstartjob_s */ ++ ++typedef struct { ++ u32 user_job_ptr; /**< [out] identifier for the job in user space */ ++ _mali_uk_job_status status; /**< [out] status of finished job */ ++ u32 heap_current_addr; /**< [out] value of the GP PLB PL heap start address register */ ++ u32 perf_counter0; /**< [out] value of performance counter 0 (see ARM DDI0415A) */ ++ u32 perf_counter1; /**< [out] value of performance counter 1 (see ARM DDI0415A) */ ++} _mali_uk_gp_job_finished_s; ++ ++typedef struct { ++ u32 user_job_ptr; /**< [out] identifier for the job in user space */ ++ u32 cookie; /**< [out] identifier for the core in kernel space on which the job stalled */ ++} _mali_uk_gp_job_suspended_s; ++ ++/** @} */ /* end group _mali_uk_gp */ ++ ++ ++/** @defgroup _mali_uk_pp U/K Fragment Processor ++ * @{ */ ++ ++#define _MALI_PP_MAX_SUB_JOBS 8 ++ ++#define _MALI_PP_MAX_FRAME_REGISTERS ((0x058/4)+1) ++ ++#define _MALI_PP_MAX_WB_REGISTERS ((0x02C/4)+1) ++ ++#define _MALI_DLBU_MAX_REGISTERS 4 ++ ++/** Flag for _mali_uk_pp_start_job_s */ ++#define _MALI_PP_JOB_FLAG_NO_NOTIFICATION (1<<0) ++#define _MALI_PP_JOB_FLAG_IS_WINDOW_SURFACE (1<<1) ++ ++/** @defgroup _mali_uk_ppstartjob_s Fragment Processor Start Job ++ * @{ */ ++ ++/** @brief Arguments for _mali_ukk_pp_start_job() ++ * ++ * To start a Fragment Processor job ++ * - associate the request with a reference to a mali_pp_job by setting ++ * @c user_job_ptr to the address of the @c mali_pp_job of the job. ++ * - set @c priority to the priority of the mali_pp_job ++ * - specify a timeout for the job by setting @c watchdog_msecs to the number of ++ * milliseconds the job is allowed to run. Specifying a value of 0 selects the ++ * default timeout in use by the device driver. ++ * - copy the frame registers from the @c mali_pp_job into @c frame_registers. ++ * For MALI200 you also need to copy the write back 0,1 and 2 registers. ++ * - set the @c perf_counter_flag, @c perf_counter_src0 and @c perf_counter_src1 to zero ++ * for a non-instrumented build. For an instrumented build you can use up ++ * to two performance counters. Set the corresponding bit in @c perf_counter_flag ++ * to enable them. @c perf_counter_src0 and @c perf_counter_src1 specify ++ * the source of what needs to get counted (e.g. number of vertex loader ++ * cache hits). For source id values, see ARM DDI0415A, Table 3-60. ++ * - pass in the user-kernel context in @c ctx that was returned from _mali_ukk_open() ++ * ++ * When _mali_ukk_pp_start_job() returns @c _MALI_OSK_ERR_OK, @c status contains the ++ * result of the request (see \ref _mali_uk_start_job_status). If the job could ++ * not get started (@c _MALI_UK_START_JOB_NOT_STARTED_DO_REQUEUE) it should be ++ * tried again. ++ * ++ * After the job has started, _mali_wait_for_notification() will be notified ++ * when the job finished. The notification will contain a ++ * @c _mali_uk_pp_job_finished_s result. It contains the @c user_job_ptr ++ * identifier used to start the job with, the job @c status (see \ref _mali_uk_job_status), ++ * the number of milliseconds the job took to render, and values of core registers ++ * when the job finished (irq status, performance counters, renderer list ++ * address). A job has finished succesfully when its status is ++ * @c _MALI_UK_JOB_STATUS_FINISHED. If the hardware detected a timeout while rendering ++ * the job, or software detected the job is taking more than @c watchdog_msecs to ++ * complete, the status will indicate @c _MALI_UK_JOB_STATUS_HANG. ++ * If the hardware detected a bus error while accessing memory associated with the ++ * job, status will indicate @c _MALI_UK_JOB_STATUS_SEG_FAULT. ++ * status will indicate @c _MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to ++ * stop the job but the job didn't start on the hardware yet, e.g. when the ++ * driver shutdown. ++ * ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 user_job_ptr; /**< [in] identifier for the job in user space */ ++ u32 priority; /**< [in] job priority. A lower number means higher priority */ ++ u32 frame_registers[_MALI_PP_MAX_FRAME_REGISTERS]; /**< [in] core specific registers associated with first sub job, see ARM DDI0415A */ ++ u32 frame_registers_addr_frame[_MALI_PP_MAX_SUB_JOBS - 1]; /**< [in] ADDR_FRAME registers for sub job 1-7 */ ++ u32 frame_registers_addr_stack[_MALI_PP_MAX_SUB_JOBS - 1]; /**< [in] ADDR_STACK registers for sub job 1-7 */ ++ u32 wb0_registers[_MALI_PP_MAX_WB_REGISTERS]; ++ u32 wb1_registers[_MALI_PP_MAX_WB_REGISTERS]; ++ u32 wb2_registers[_MALI_PP_MAX_WB_REGISTERS]; ++ u32 dlbu_registers[_MALI_DLBU_MAX_REGISTERS]; /**< [in] Dynamic load balancing unit registers */ ++ u32 num_cores; /**< [in] Number of cores to set up (valid range: 1-4) */ ++ u32 perf_counter_flag; /**< [in] bitmask indicating which performance counters to enable, see \ref _MALI_PERFORMANCE_COUNTER_FLAG_SRC0_ENABLE and related macro definitions */ ++ u32 perf_counter_src0; /**< [in] source id for performance counter 0 (see ARM DDI0415A, Table 3-60) */ ++ u32 perf_counter_src1; /**< [in] source id for performance counter 1 (see ARM DDI0415A, Table 3-60) */ ++ u32 frame_builder_id; /**< [in] id of the originating frame builder */ ++ u32 flush_id; /**< [in] flush id within the originating frame builder */ ++ u32 flags; /**< [in] See _MALI_PP_JOB_FLAG_* for a list of avaiable flags */ ++ u32 tilesx; /**< [in] number of tiles in the x direction (needed for heatmap generation */ ++ u32 tilesy; /**< [in] number of tiles in y direction (needed for reading the heatmap memory) */ ++ u32 heatmap_mem; /**< [in] memory address to store counter values per tile (aka heatmap) */ ++ u32 num_memory_cookies; /**< [in] number of memory cookies attached to job */ ++ u32 *memory_cookies; /**< [in] memory cookies attached to job */ ++ _mali_uk_fence_t fence; /**< [in] fence this job must wait on */ ++ u32 *timeline_point_ptr; /**< [in,out] pointer to location where point on pp timeline for this job will be written */ ++} _mali_uk_pp_start_job_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_gp_start_job_s *gp_args; /**< [in,out] GP uk arguments (see _mali_uk_gp_start_job_s) */ ++ _mali_uk_pp_start_job_s *pp_args; /**< [in,out] PP uk arguments (see _mali_uk_pp_start_job_s) */ ++} _mali_uk_pp_and_gp_start_job_s; ++ ++/** @} */ /* end group _mali_uk_ppstartjob_s */ ++ ++typedef struct { ++ u32 user_job_ptr; /**< [out] identifier for the job in user space */ ++ _mali_uk_job_status status; /**< [out] status of finished job */ ++ u32 perf_counter0[_MALI_PP_MAX_SUB_JOBS]; /**< [out] value of perfomance counter 0 (see ARM DDI0415A), one for each sub job */ ++ u32 perf_counter1[_MALI_PP_MAX_SUB_JOBS]; /**< [out] value of perfomance counter 1 (see ARM DDI0415A), one for each sub job */ ++ u32 perf_counter_src0; ++ u32 perf_counter_src1; ++} _mali_uk_pp_job_finished_s; ++ ++typedef struct { ++ u32 number_of_enabled_cores; /**< [out] the new number of enabled cores */ ++} _mali_uk_pp_num_cores_changed_s; ++ ++ ++ ++/** ++ * Flags to indicate write-back units ++ */ ++typedef enum { ++ _MALI_UK_PP_JOB_WB0 = 1, ++ _MALI_UK_PP_JOB_WB1 = 2, ++ _MALI_UK_PP_JOB_WB2 = 4, ++} _mali_uk_pp_job_wbx_flag; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 fb_id; /**< [in] Frame builder ID of job to disable WB units for */ ++ u32 wb0_memory; ++ u32 wb1_memory; ++ u32 wb2_memory; ++} _mali_uk_pp_disable_wb_s; ++ ++ ++/** @} */ /* end group _mali_uk_pp */ ++ ++/** @defgroup _mali_uk_soft_job U/K Soft Job ++ * @{ */ ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 type; /**< [in] type of soft job */ ++ u32 user_job; /**< [in] identifier for the job in user space */ ++ u32 *job_id_ptr; /**< [in,out] pointer to location where job id will be written */ ++ _mali_uk_fence_t fence; /**< [in] fence this job must wait on */ ++ u32 point; /**< [out] point on soft timeline for this job */ ++} _mali_uk_soft_job_start_s; ++ ++typedef struct { ++ u32 user_job; /**< [out] identifier for the job in user space */ ++} _mali_uk_soft_job_activated_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 job_id; /**< [in] id for soft job */ ++} _mali_uk_soft_job_signal_s; ++ ++/** @} */ /* end group _mali_uk_soft_job */ ++ ++/** @addtogroup _mali_uk_core U/K Core ++ * @{ */ ++ ++/** @defgroup _mali_uk_waitfornotification_s Wait For Notification ++ * @{ */ ++ ++/** @brief Notification type encodings ++ * ++ * Each Notification type is an ordered pair of (subsystem,id), and is unique. ++ * ++ * The encoding of subsystem,id into a 32-bit word is: ++ * encoding = (( subsystem << _MALI_NOTIFICATION_SUBSYSTEM_SHIFT ) & _MALI_NOTIFICATION_SUBSYSTEM_MASK) ++ * | (( id << _MALI_NOTIFICATION_ID_SHIFT ) & _MALI_NOTIFICATION_ID_MASK) ++ * ++ * @see _mali_uk_wait_for_notification_s ++ */ ++typedef enum { ++ /** core notifications */ ++ ++ _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x20, ++ _MALI_NOTIFICATION_APPLICATION_QUIT = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x40, ++ _MALI_NOTIFICATION_SETTINGS_CHANGED = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x80, ++ _MALI_NOTIFICATION_SOFT_ACTIVATED = (_MALI_UK_CORE_SUBSYSTEM << 16) | 0x100, ++ ++ /** Fragment Processor notifications */ ++ ++ _MALI_NOTIFICATION_PP_FINISHED = (_MALI_UK_PP_SUBSYSTEM << 16) | 0x10, ++ _MALI_NOTIFICATION_PP_NUM_CORE_CHANGE = (_MALI_UK_PP_SUBSYSTEM << 16) | 0x20, ++ ++ /** Vertex Processor notifications */ ++ ++ _MALI_NOTIFICATION_GP_FINISHED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x10, ++ _MALI_NOTIFICATION_GP_STALLED = (_MALI_UK_GP_SUBSYSTEM << 16) | 0x20, ++ ++} _mali_uk_notification_type; ++ ++/** to assist in splitting up 32-bit notification value in subsystem and id value */ ++#define _MALI_NOTIFICATION_SUBSYSTEM_MASK 0xFFFF0000 ++#define _MALI_NOTIFICATION_SUBSYSTEM_SHIFT 16 ++#define _MALI_NOTIFICATION_ID_MASK 0x0000FFFF ++#define _MALI_NOTIFICATION_ID_SHIFT 0 ++ ++ ++/** @brief Enumeration of possible settings which match mali_setting_t in user space ++ * ++ * ++ */ ++typedef enum { ++ _MALI_UK_USER_SETTING_SW_EVENTS_ENABLE = 0, ++ _MALI_UK_USER_SETTING_COLORBUFFER_CAPTURE_ENABLED, ++ _MALI_UK_USER_SETTING_DEPTHBUFFER_CAPTURE_ENABLED, ++ _MALI_UK_USER_SETTING_STENCILBUFFER_CAPTURE_ENABLED, ++ _MALI_UK_USER_SETTING_PER_TILE_COUNTERS_CAPTURE_ENABLED, ++ _MALI_UK_USER_SETTING_BUFFER_CAPTURE_COMPOSITOR, ++ _MALI_UK_USER_SETTING_BUFFER_CAPTURE_WINDOW, ++ _MALI_UK_USER_SETTING_BUFFER_CAPTURE_OTHER, ++ _MALI_UK_USER_SETTING_BUFFER_CAPTURE_N_FRAMES, ++ _MALI_UK_USER_SETTING_BUFFER_CAPTURE_RESIZE_FACTOR, ++ _MALI_UK_USER_SETTING_SW_COUNTER_ENABLED, ++ _MALI_UK_USER_SETTING_MAX, ++} _mali_uk_user_setting_t; ++ ++/* See mali_user_settings_db.c */ ++extern const char *_mali_uk_user_setting_descriptions[]; ++#define _MALI_UK_USER_SETTING_DESCRIPTIONS \ ++{ \ ++ "sw_events_enable", \ ++ "colorbuffer_capture_enable", \ ++ "depthbuffer_capture_enable", \ ++ "stencilbuffer_capture_enable", \ ++ "per_tile_counters_enable", \ ++ "buffer_capture_compositor", \ ++ "buffer_capture_window", \ ++ "buffer_capture_other", \ ++ "buffer_capture_n_frames", \ ++ "buffer_capture_resize_factor", \ ++ "sw_counters_enable", \ ++}; ++ ++/** @brief struct to hold the value to a particular setting as seen in the kernel space ++ */ ++typedef struct { ++ _mali_uk_user_setting_t setting; ++ u32 value; ++} _mali_uk_settings_changed_s; ++ ++/** @brief Arguments for _mali_ukk_wait_for_notification() ++ * ++ * On successful return from _mali_ukk_wait_for_notification(), the members of ++ * this structure will indicate the reason for notification. ++ * ++ * Specifically, the source of the notification can be identified by the ++ * subsystem and id fields of the mali_uk_notification_type in the code.type ++ * member. The type member is encoded in a way to divide up the types into a ++ * subsystem field, and a per-subsystem ID field. See ++ * _mali_uk_notification_type for more information. ++ * ++ * Interpreting the data union member depends on the notification type: ++ * ++ * - type == _MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS ++ * - The kernel side is shutting down. No further ++ * _mali_uk_wait_for_notification() calls should be made. ++ * - In this case, the value of the data union member is undefined. ++ * - This is used to indicate to the user space client that it should close ++ * the connection to the Mali Device Driver. ++ * - type == _MALI_NOTIFICATION_PP_FINISHED ++ * - The notification data is of type _mali_uk_pp_job_finished_s. It contains the user_job_ptr ++ * identifier used to start the job with, the job status, the number of milliseconds the job took to render, ++ * and values of core registers when the job finished (irq status, performance counters, renderer list ++ * address). ++ * - A job has finished succesfully when its status member is _MALI_UK_JOB_STATUS_FINISHED. ++ * - If the hardware detected a timeout while rendering the job, or software detected the job is ++ * taking more than watchdog_msecs (see _mali_ukk_pp_start_job()) to complete, the status member will ++ * indicate _MALI_UK_JOB_STATUS_HANG. ++ * - If the hardware detected a bus error while accessing memory associated with the job, status will ++ * indicate _MALI_UK_JOB_STATUS_SEG_FAULT. ++ * - Status will indicate MALI_UK_JOB_STATUS_NOT_STARTED if the driver had to stop the job but the job ++ * didn't start the hardware yet, e.g. when the driver closes. ++ * - type == _MALI_NOTIFICATION_GP_FINISHED ++ * - The notification data is of type _mali_uk_gp_job_finished_s. The notification is similar to that of ++ * type == _MALI_NOTIFICATION_PP_FINISHED, except that several other GP core register values are returned. ++ * The status values have the same meaning for type == _MALI_NOTIFICATION_PP_FINISHED. ++ * - type == _MALI_NOTIFICATION_GP_STALLED ++ * - The nofication data is of type _mali_uk_gp_job_suspended_s. It contains the user_job_ptr ++ * identifier used to start the job with, the reason why the job stalled and a cookie to identify the core on ++ * which the job stalled. ++ * - The reason member of gp_job_suspended is set to _MALIGP_JOB_SUSPENDED_OUT_OF_MEMORY ++ * when the polygon list builder unit has run out of memory. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_notification_type type; /**< [out] Type of notification available */ ++ union { ++ _mali_uk_gp_job_suspended_s gp_job_suspended;/**< [out] Notification data for _MALI_NOTIFICATION_GP_STALLED notification type */ ++ _mali_uk_gp_job_finished_s gp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_GP_FINISHED notification type */ ++ _mali_uk_pp_job_finished_s pp_job_finished; /**< [out] Notification data for _MALI_NOTIFICATION_PP_FINISHED notification type */ ++ _mali_uk_settings_changed_s setting_changed;/**< [out] Notification data for _MALI_NOTIFICAATION_SETTINGS_CHANGED notification type */ ++ _mali_uk_soft_job_activated_s soft_job_activated; /**< [out] Notification data for _MALI_NOTIFICATION_SOFT_ACTIVATED notification type */ ++ } data; ++} _mali_uk_wait_for_notification_s; ++ ++/** @brief Arguments for _mali_ukk_post_notification() ++ * ++ * Posts the specified notification to the notification queue for this application. ++ * This is used to send a quit message to the callback thread. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_notification_type type; /**< [in] Type of notification to post */ ++} _mali_uk_post_notification_s; ++ ++/** @} */ /* end group _mali_uk_waitfornotification_s */ ++ ++/** @defgroup _mali_uk_getapiversion_s Get API Version ++ * @{ */ ++ ++/** helpers for Device Driver API version handling */ ++ ++/** @brief Encode a version ID from a 16-bit input ++ * ++ * @note the input is assumed to be 16 bits. It must not exceed 16 bits. */ ++#define _MAKE_VERSION_ID(x) (((x) << 16UL) | (x)) ++ ++/** @brief Check whether a 32-bit value is likely to be Device Driver API ++ * version ID. */ ++#define _IS_VERSION_ID(x) (((x) & 0xFFFF) == (((x) >> 16UL) & 0xFFFF)) ++ ++/** @brief Decode a 16-bit version number from a 32-bit Device Driver API version ++ * ID */ ++#define _GET_VERSION(x) (((x) >> 16UL) & 0xFFFF) ++ ++/** @brief Determine whether two 32-bit encoded version IDs match */ ++#define _IS_API_MATCH(x, y) (IS_VERSION_ID((x)) && IS_VERSION_ID((y)) && (GET_VERSION((x)) == GET_VERSION((y)))) ++ ++/** ++ * API version define. ++ * Indicates the version of the kernel API ++ * The version is a 16bit integer incremented on each API change. ++ * The 16bit integer is stored twice in a 32bit integer ++ * For example, for version 1 the value would be 0x00010001 ++ */ ++#define _MALI_API_VERSION 401 ++#define _MALI_UK_API_VERSION _MAKE_VERSION_ID(_MALI_API_VERSION) ++ ++/** ++ * The API version is a 16-bit integer stored in both the lower and upper 16-bits ++ * of a 32-bit value. The 16-bit API version value is incremented on each API ++ * change. Version 1 would be 0x00010001. Used in _mali_uk_get_api_version_s. ++ */ ++typedef u32 _mali_uk_api_version; ++ ++/** @brief Arguments for _mali_uk_get_api_version() ++ * ++ * The user-side interface version must be written into the version member, ++ * encoded using _MAKE_VERSION_ID(). It will be compared to the API version of ++ * the kernel-side interface. ++ * ++ * On successful return, the version member will be the API version of the ++ * kernel-side interface. _MALI_UK_API_VERSION macro defines the current version ++ * of the API. ++ * ++ * The compatible member must be checked to see if the version of the user-side ++ * interface is compatible with the kernel-side interface, since future versions ++ * of the interface may be backwards compatible. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_api_version version; /**< [in,out] API version of user-side interface. */ ++ int compatible; /**< [out] @c 1 when @version is compatible, @c 0 otherwise */ ++} _mali_uk_get_api_version_s; ++/** @} */ /* end group _mali_uk_getapiversion_s */ ++ ++/** @defgroup _mali_uk_get_user_settings_s Get user space settings */ ++ ++/** @brief struct to keep the matching values of the user space settings within certain context ++ * ++ * Each member of the settings array corresponds to a matching setting in the user space and its value is the value ++ * of that particular setting. ++ * ++ * All settings are given reference to the context pointed to by the ctx pointer. ++ * ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 settings[_MALI_UK_USER_SETTING_MAX]; /**< [out] The values for all settings */ ++} _mali_uk_get_user_settings_s; ++ ++/** @brief struct to hold the value of a particular setting from the user space within a given context ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_user_setting_t setting; /**< [in] setting to get */ ++ u32 value; /**< [out] value of setting */ ++} _mali_uk_get_user_setting_s; ++ ++/** @brief Arguments for _mali_ukk_request_high_priority() */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++} _mali_uk_request_high_priority_s; ++ ++/** @} */ /* end group _mali_uk_core */ ++ ++ ++/** @defgroup _mali_uk_memory U/K Memory ++ * @{ */ ++ ++/** Flag for _mali_uk_map_external_mem_s, _mali_uk_attach_ump_mem_s and _mali_uk_attach_dma_buf_s */ ++#define _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE (1<<0) ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 phys_addr; /**< [in] physical address */ ++ u32 size; /**< [in] size */ ++ u32 mali_address; /**< [in] mali address to map the physical memory to */ ++ u32 rights; /**< [in] rights necessary for accessing memory */ ++ u32 flags; /**< [in] flags, see \ref _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE */ ++ u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ ++} _mali_uk_map_external_mem_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ ++} _mali_uk_unmap_external_mem_s; ++ ++/** @note This is identical to _mali_uk_map_external_mem_s above, however phys_addr is replaced by memory descriptor */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 mem_fd; /**< [in] Memory descriptor */ ++ u32 size; /**< [in] size */ ++ u32 mali_address; /**< [in] mali address to map the physical memory to */ ++ u32 rights; /**< [in] rights necessary for accessing memory */ ++ u32 flags; /**< [in] flags, see \ref _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE */ ++ u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ ++} _mali_uk_attach_dma_buf_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 mem_fd; /**< [in] Memory descriptor */ ++ u32 size; /**< [out] size */ ++} _mali_uk_dma_buf_get_size_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 cookie; /**< [in] identifier for mapped memory object in kernel space */ ++} _mali_uk_release_dma_buf_s; ++ ++/** @note This is identical to _mali_uk_map_external_mem_s above, however phys_addr is replaced by secure_id */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< [in] secure id */ ++ u32 size; /**< [in] size */ ++ u32 mali_address; /**< [in] mali address to map the physical memory to */ ++ u32 rights; /**< [in] rights necessary for accessing memory */ ++ u32 flags; /**< [in] flags, see \ref _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE */ ++ u32 cookie; /**< [out] identifier for mapped memory object in kernel space */ ++} _mali_uk_attach_ump_mem_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 cookie; /**< [in] identifier for mapped memory object in kernel space */ ++} _mali_uk_release_ump_mem_s; ++ ++/** @brief Arguments for _mali_ukk_va_to_mali_pa() ++ * ++ * if size is zero or not a multiple of the system's page size, it will be ++ * rounded up to the next multiple of the page size. This will occur before ++ * any other use of the size parameter. ++ * ++ * if va is not PAGE_SIZE aligned, it will be rounded down to the next page ++ * boundary. ++ * ++ * The range (va) to ((u32)va)+(size-1) inclusive will be checked for physical ++ * contiguity. ++ * ++ * The implementor will check that the entire physical range is allowed to be mapped ++ * into user-space. ++ * ++ * Failure will occur if either of the above are not satisfied. ++ * ++ * Otherwise, the physical base address of the range is returned through pa, ++ * va is updated to be page aligned, and size is updated to be a non-zero ++ * multiple of the system's pagesize. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *va; /**< [in,out] Virtual address of the start of the range */ ++ u32 pa; /**< [out] Physical base address of the range */ ++ u32 size; /**< [in,out] Size of the range, in bytes. */ ++} _mali_uk_va_to_mali_pa_s; ++ ++/** ++ * @brief Arguments for _mali_uk[uk]_mem_write_safe() ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ const void *src; /**< [in] Pointer to source data */ ++ void *dest; /**< [in] Destination Mali buffer */ ++ u32 size; /**< [in,out] Number of bytes to write/copy on input, number of bytes actually written/copied on output */ ++} _mali_uk_mem_write_safe_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 size; /**< [out] size of MMU page table information (registers + page tables) */ ++} _mali_uk_query_mmu_page_table_dump_size_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 size; /**< [in] size of buffer to receive mmu page table information */ ++ void *buffer; /**< [in,out] buffer to receive mmu page table information */ ++ u32 register_writes_size; /**< [out] size of MMU register dump */ ++ u32 *register_writes; /**< [out] pointer within buffer where MMU register dump is stored */ ++ u32 page_table_dump_size; /**< [out] size of MMU page table dump */ ++ u32 *page_table_dump; /**< [out] pointer within buffer where MMU page table dump is stored */ ++} _mali_uk_dump_mmu_page_table_s; ++ ++/** @} */ /* end group _mali_uk_memory */ ++ ++ ++/** @addtogroup _mali_uk_pp U/K Fragment Processor ++ * @{ */ ++ ++/** @brief Arguments for _mali_ukk_get_pp_number_of_cores() ++ * ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * - Upon successful return from _mali_ukk_get_pp_number_of_cores(), @c number_of_cores ++ * will contain the number of Fragment Processor cores in the system. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 number_of_total_cores; /**< [out] Total number of Fragment Processor cores in the system */ ++ u32 number_of_enabled_cores; /**< [out] Number of enabled Fragment Processor cores */ ++} _mali_uk_get_pp_number_of_cores_s; ++ ++/** @brief Arguments for _mali_ukk_get_pp_core_version() ++ * ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * - Upon successful return from _mali_ukk_get_pp_core_version(), @c version contains ++ * the version that all Fragment Processor cores are compatible with. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_core_version version; /**< [out] version returned from core, see \ref _mali_core_version */ ++} _mali_uk_get_pp_core_version_s; ++ ++/** @} */ /* end group _mali_uk_pp */ ++ ++ ++/** @addtogroup _mali_uk_gp U/K Vertex Processor ++ * @{ */ ++ ++/** @brief Arguments for _mali_ukk_get_gp_number_of_cores() ++ * ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * - Upon successful return from _mali_ukk_get_gp_number_of_cores(), @c number_of_cores ++ * will contain the number of Vertex Processor cores in the system. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 number_of_cores; /**< [out] number of Vertex Processor cores in the system */ ++} _mali_uk_get_gp_number_of_cores_s; ++ ++/** @brief Arguments for _mali_ukk_get_gp_core_version() ++ * ++ * - pass in the user-kernel context @c ctx that was returned from _mali_ukk_open() ++ * - Upon successful return from _mali_ukk_get_gp_core_version(), @c version contains ++ * the version that all Vertex Processor cores are compatible with. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_core_version version; /**< [out] version returned from core, see \ref _mali_core_version */ ++} _mali_uk_get_gp_core_version_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 limit; /**< [in,out] The desired limit for number of events to record on input, actual limit on output */ ++} _mali_uk_profiling_start_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 event_id; /**< [in] event id to register (see enum mali_profiling_events for values) */ ++ u32 data[5]; /**< [in] event specific data */ ++} _mali_uk_profiling_add_event_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 count; /**< [out] The number of events sampled */ ++} _mali_uk_profiling_stop_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 index; /**< [in] which index to get (starting at zero) */ ++ u64 timestamp; /**< [out] timestamp of event */ ++ u32 event_id; /**< [out] event id of event (see enum mali_profiling_events for values) */ ++ u32 data[5]; /**< [out] event specific data */ ++} _mali_uk_profiling_get_event_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++} _mali_uk_profiling_clear_s; ++ ++/** @} */ /* end group _mali_uk_gp */ ++ ++ ++/** @addtogroup _mali_uk_memory U/K Memory ++ * @{ */ ++ ++/** @brief Arguments to _mali_ukk_mem_mmap() ++ * ++ * Use of the phys_addr member depends on whether the driver is compiled for ++ * Mali-MMU or nonMMU: ++ * - in the nonMMU case, this is the physical address of the memory as seen by ++ * the CPU (which may be a constant offset from that used by Mali) ++ * - in the MMU case, this is the Mali Virtual base address of the memory to ++ * allocate, and the particular physical pages used to back the memory are ++ * entirely determined by _mali_ukk_mem_mmap(). The details of the physical pages ++ * are not reported to user-space for security reasons. ++ * ++ * The cookie member must be stored for use later when freeing the memory by ++ * calling _mali_ukk_mem_munmap(). In the Mali-MMU case, the cookie is secure. ++ * ++ * The ukk_private word must be set to zero when calling from user-space. On ++ * Kernel-side, the OS implementation of the U/K interface can use it to ++ * communicate data to the OS implementation of the OSK layer. In particular, ++ * _mali_ukk_get_big_block() directly calls _mali_ukk_mem_mmap directly, and ++ * will communicate its own ukk_private word through the ukk_private member ++ * here. The common code itself will not inspect or modify the ukk_private ++ * word, and so it may be safely used for whatever purposes necessary to ++ * integrate Mali Memory handling into the OS. ++ * ++ * The uku_private member is currently reserved for use by the user-side ++ * implementation of the U/K interface. Its value must be zero. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *mapping; /**< [out] Returns user-space virtual address for the mapping */ ++ u32 size; /**< [in] Size of the requested mapping */ ++ u32 phys_addr; /**< [in] Physical address - could be offset, depending on caller+callee convention */ ++ u32 cookie; /**< [out] Returns a cookie for use in munmap calls */ ++ void *uku_private; /**< [in] User-side Private word used by U/K interface */ ++ void *ukk_private; /**< [in] Kernel-side Private word used by U/K interface */ ++ mali_memory_cache_settings cache_settings; /**< [in] Option to set special cache flags, tuning L2 efficency */ ++} _mali_uk_mem_mmap_s; ++ ++/** @brief Arguments to _mali_ukk_mem_munmap() ++ * ++ * The cookie and mapping members must be that returned from the same previous ++ * call to _mali_ukk_mem_mmap(). The size member must correspond to cookie ++ * and mapping - that is, it must be the value originally supplied to a call to ++ * _mali_ukk_mem_mmap that returned the values of mapping and cookie. ++ * ++ * An error will be returned if an attempt is made to unmap only part of the ++ * originally obtained range, or to unmap more than was originally obtained. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *mapping; /**< [in] The mapping returned from mmap call */ ++ u32 size; /**< [in] The size passed to mmap call */ ++ u32 cookie; /**< [in] Cookie from mmap call */ ++} _mali_uk_mem_munmap_s; ++/** @} */ /* end group _mali_uk_memory */ ++ ++/** @defgroup _mali_uk_vsync U/K VSYNC Wait Reporting Module ++ * @{ */ ++ ++/** @brief VSYNC events ++ * ++ * These events are reported when DDK starts to wait for vsync and when the ++ * vsync has occured and the DDK can continue on the next frame. ++ */ ++typedef enum _mali_uk_vsync_event { ++ _MALI_UK_VSYNC_EVENT_BEGIN_WAIT = 0, ++ _MALI_UK_VSYNC_EVENT_END_WAIT ++} _mali_uk_vsync_event; ++ ++/** @brief Arguments to _mali_ukk_vsync_event() ++ * ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_vsync_event event; /**< [in] VSYNCH event type */ ++} _mali_uk_vsync_event_report_s; ++ ++/** @} */ /* end group _mali_uk_vsync */ ++ ++/** @defgroup _mali_uk_sw_counters_report U/K Software Counter Reporting ++ * @{ */ ++ ++/** @brief Software counter values ++ * ++ * Values recorded for each of the software counters during a single renderpass. ++ */ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32* counters; /**< [in] The array of counter values */ ++ u32 num_counters; /**< [in] The number of elements in counters array */ ++} _mali_uk_sw_counters_report_s; ++ ++/** @} */ /* end group _mali_uk_sw_counters_report */ ++ ++/** @defgroup _mali_uk_timeline U/K Mali Timeline ++ * @{ */ ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 timeline; /**< [in] timeline id */ ++ u32 point; /**< [out] latest point on timeline */ ++} _mali_uk_timeline_get_latest_point_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_fence_t fence; /**< [in] fence */ ++ u32 timeout; /**< [in] timeout (0 for no wait, -1 for blocking) */ ++ u32 status; /**< [out] status of fence (1 if signaled, 0 if timeout) */ ++} _mali_uk_timeline_wait_s; ++ ++typedef struct { ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ _mali_uk_fence_t fence; /**< [in] mali fence to create linux sync fence from */ ++ s32 sync_fd; /**< [out] file descriptor for new linux sync fence */ ++} _mali_uk_timeline_create_sync_fence_s; ++ ++/** @} */ /* end group _mali_uk_timeline */ ++ ++/** @} */ /* end group u_k_api */ ++ ++/** @} */ /* end group uddapi */ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UTGARD_UK_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/license/gpl/mali_kernel_license.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/license/gpl/mali_kernel_license.h +new file mode 100644 +index 0000000..009acc4 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/license/gpl/mali_kernel_license.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_kernel_license.h ++ * Defines for the macro MODULE_LICENSE. ++ */ ++ ++#ifndef __MALI_KERNEL_LICENSE_H__ ++#define __MALI_KERNEL_LICENSE_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define MALI_KERNEL_LINUX_LICENSE "GPL" ++#define MALI_LICENSE_IS_GPL 1 ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_KERNEL_LICENSE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_device_pause_resume.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_device_pause_resume.c +new file mode 100644 +index 0000000..440602e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_device_pause_resume.c +@@ -0,0 +1,38 @@ ++/** ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_device_pause_resume.c ++ * Implementation of the Mali pause/resume functionality ++ */ ++ ++#include ++#include ++#include "mali_gp_scheduler.h" ++#include "mali_pp_scheduler.h" ++ ++void mali_dev_pause(void) ++{ ++ mali_gp_scheduler_suspend(); ++ mali_pp_scheduler_suspend(); ++ mali_group_power_off(MALI_FALSE); ++ mali_l2_cache_pause_all(MALI_TRUE); ++} ++ ++EXPORT_SYMBOL(mali_dev_pause); ++ ++void mali_dev_resume(void) ++{ ++ mali_l2_cache_pause_all(MALI_FALSE); ++ mali_gp_scheduler_resume(); ++ mali_pp_scheduler_resume(); ++} ++ ++EXPORT_SYMBOL(mali_dev_resume); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.c +new file mode 100644 +index 0000000..43bc697 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.c +@@ -0,0 +1,821 @@ ++/** ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_kernel_linux.c ++ * Implementation of the Linux device driver entrypoints ++ */ ++#include /* kernel module definitions */ ++#include /* file system operations */ ++#include /* character device definitions */ ++#include /* memory manager definitions */ ++#include ++#include ++#include ++#include "mali_kernel_license.h" ++#include ++#include ++#include ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_kernel_core.h" ++#include "mali_osk.h" ++#include "mali_kernel_linux.h" ++#include "mali_ukk.h" ++#include "mali_ukk_wrappers.h" ++#include "mali_kernel_sysfs.h" ++#include "mali_pm.h" ++#include "mali_kernel_license.h" ++#include "mali_memory.h" ++#include "mali_memory_dma_buf.h" ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++#include "mali_profiling_internal.h" ++#endif ++ ++/* Streamline support for the Mali driver */ ++#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_MALI400_PROFILING) ++/* Ask Linux to create the tracepoints */ ++#define CREATE_TRACE_POINTS ++#include "mali_linux_trace.h" ++#endif /* CONFIG_TRACEPOINTS */ ++ ++extern struct attribute_group gpu_attribute_group; ++ ++/* from the __malidrv_build_info.c file that is generated during build */ ++extern const char *__malidrv_build_info(void); ++ ++extern void enable_gpu_clk(void); ++extern void disable_gpu_clk(void); ++extern void mali_dvfs_change(int level, int up_flag); ++ ++/* Module parameter to control log level */ ++int mali_debug_level = 2; ++module_param(mali_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ ++MODULE_PARM_DESC(mali_debug_level, "Higher number, more dmesg output"); ++ ++extern int mali_max_job_runtime; ++module_param(mali_max_job_runtime, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_max_job_runtime, "Maximum allowed job runtime in msecs.\nJobs will be killed after this no matter what"); ++ ++extern int mali_l2_max_reads; ++module_param(mali_l2_max_reads, int, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_l2_max_reads, "Maximum reads for Mali L2 cache"); ++ ++extern unsigned int mali_dedicated_mem_start; ++module_param(mali_dedicated_mem_start, uint, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_dedicated_mem_start, "Physical start address of dedicated Mali GPU memory."); ++ ++extern unsigned int mali_dedicated_mem_size; ++module_param(mali_dedicated_mem_size, uint, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_dedicated_mem_size, "Size of dedicated Mali GPU memory."); ++ ++extern unsigned int mali_shared_mem_size; ++module_param(mali_shared_mem_size, uint, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_shared_mem_size, "Size of shared Mali GPU memory."); ++ ++#if defined(CONFIG_MALI400_PROFILING) ++extern int mali_boot_profiling; ++module_param(mali_boot_profiling, int, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_boot_profiling, "Start profiling as a part of Mali driver initialization"); ++#endif ++ ++extern int mali_max_pp_cores_group_1; ++module_param(mali_max_pp_cores_group_1, int, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_max_pp_cores_group_1, "Limit the number of PP cores to use from first PP group."); ++ ++extern int mali_max_pp_cores_group_2; ++module_param(mali_max_pp_cores_group_2, int, S_IRUSR | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_max_pp_cores_group_2, "Limit the number of PP cores to use from second PP group (Mali-450 only)."); ++ ++#if defined(CONFIG_MALI400_POWER_PERFORMANCE_POLICY) ++/** the max fps the same as display vsync default 60, can set by module insert parameter */ ++extern int mali_max_system_fps; ++module_param(mali_max_system_fps, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_max_system_fps, "Max system fps the same as display VSYNC."); ++ ++/** a lower limit on their desired FPS default 58, can set by module insert parameter*/ ++extern int mali_desired_fps; ++module_param(mali_desired_fps, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); ++MODULE_PARM_DESC(mali_desired_fps, "A bit lower than max_system_fps which user desired fps"); ++#endif ++ ++#if MALI_ENABLE_CPU_CYCLES ++#include ++#include ++#include ++static struct timer_list mali_init_cpu_clock_timers[8]; ++static u32 mali_cpu_clock_last_value[8] = {0,}; ++#endif ++ ++/* Export symbols from common code: mali_user_settings.c */ ++#include "mali_user_settings_db.h" ++EXPORT_SYMBOL(mali_set_user_setting); ++EXPORT_SYMBOL(mali_get_user_setting); ++ ++static char mali_dev_name[] = "mali"; /* should be const, but the functions we call requires non-cost */ ++ ++/* This driver only supports one Mali device, and this variable stores this single platform device */ ++struct platform_device *mali_platform_device = NULL; ++ ++/* This driver only supports one Mali device, and this variable stores the exposed misc device (/dev/mali) */ ++static struct miscdevice mali_miscdevice = { 0, }; ++ ++static int mali_miscdevice_register(struct platform_device *pdev); ++static void mali_miscdevice_unregister(void); ++ ++static int mali_open(struct inode *inode, struct file *filp); ++static int mali_release(struct inode *inode, struct file *filp); ++#ifdef HAVE_UNLOCKED_IOCTL ++static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); ++#else ++static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++#endif ++ ++static int mali_probe(struct platform_device *pdev); ++static int mali_remove(struct platform_device *pdev); ++ ++static int mali_driver_suspend_scheduler(struct device *dev); ++static int mali_driver_resume_scheduler(struct device *dev); ++ ++#ifdef CONFIG_PM_RUNTIME ++static int mali_driver_runtime_suspend(struct device *dev); ++static int mali_driver_runtime_resume(struct device *dev); ++static int mali_driver_runtime_idle(struct device *dev); ++#endif ++ ++#if defined(MALI_FAKE_PLATFORM_DEVICE) ++extern int mali_platform_device_register(void); ++extern int mali_platform_device_unregister(void); ++#endif ++extern int sun8i_mali_platform_device_register(void); ++/* Linux power management operations provided by the Mali device driver */ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) ++struct pm_ext_ops mali_dev_ext_pm_ops = { ++ .base = ++ { ++ .suspend = mali_driver_suspend_scheduler, ++ .resume = mali_driver_resume_scheduler, ++ .freeze = mali_driver_suspend_scheduler, ++ .thaw = mali_driver_resume_scheduler, ++ }, ++}; ++#else ++static const struct dev_pm_ops mali_dev_pm_ops = { ++#ifdef CONFIG_PM_RUNTIME ++ .runtime_suspend = mali_driver_runtime_suspend, ++ .runtime_resume = mali_driver_runtime_resume, ++ .runtime_idle = mali_driver_runtime_idle, ++#endif ++ .suspend = mali_driver_suspend_scheduler, ++ .resume = mali_driver_resume_scheduler, ++ .freeze = mali_driver_suspend_scheduler, ++ .thaw = mali_driver_resume_scheduler, ++ .poweroff = mali_driver_suspend_scheduler, ++}; ++#endif ++ ++/* The Mali device driver struct */ ++static struct platform_driver mali_platform_driver = { ++ .probe = mali_probe, ++ .remove = mali_remove, ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) ++ .pm = &mali_dev_ext_pm_ops, ++#endif ++ .driver = ++ { ++ .name = MALI_GPU_NAME_UTGARD, ++ .owner = THIS_MODULE, ++ .bus = &platform_bus_type, ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)) ++ .pm = &mali_dev_pm_ops, ++#endif ++ }, ++}; ++ ++/* Linux misc device operations (/dev/mali) */ ++struct file_operations mali_fops = { ++ .owner = THIS_MODULE, ++ .open = mali_open, ++ .release = mali_release, ++#ifdef HAVE_UNLOCKED_IOCTL ++ .unlocked_ioctl = mali_ioctl, ++#else ++ .ioctl = mali_ioctl, ++#endif ++ .mmap = mali_mmap ++}; ++ ++ ++#if MALI_ENABLE_CPU_CYCLES ++void mali_init_cpu_time_counters(int reset, int enable_divide_by_64) ++{ ++ /* The CPU assembly reference used is: ARM Architecture Reference Manual ARMv7-AR C.b */ ++ u32 write_value; ++ ++ /* See B4.1.116 PMCNTENSET, Performance Monitors Count Enable Set register, VMSA */ ++ /* setting p15 c9 c12 1 to 0x8000000f==CPU_CYCLE_ENABLE |EVENT_3_ENABLE|EVENT_2_ENABLE|EVENT_1_ENABLE|EVENT_0_ENABLE */ ++ asm volatile("mcr p15, 0, %0, c9, c12, 1" :: "r"(0x8000000f)); ++ ++ ++ /* See B4.1.117 PMCR, Performance Monitors Control Register. Writing to p15, c9, c12, 0 */ ++ write_value = 1<<0; /* Bit 0 set. Enable counters */ ++ if (reset) { ++ write_value |= 1<<1; /* Reset event counters */ ++ write_value |= 1<<2; /* Reset cycle counter */ ++ } ++ if (enable_divide_by_64) { ++ write_value |= 1<<3; /* Enable the Clock divider by 64 */ ++ } ++ write_value |= 1<<4; /* Export enable. Not needed */ ++ asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(write_value )); ++ ++ /* PMOVSR Overflow Flag Status Register - Clear Clock and Event overflows */ ++ asm volatile ("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f)); ++ ++ ++ /* See B4.1.124 PMUSERENR - setting p15 c9 c14 to 1" */ ++ /* User mode access to the Performance Monitors enabled. */ ++ /* Lets User space read cpu clock cycles */ ++ asm volatile( "mcr p15, 0, %0, c9, c14, 0" :: "r"(1) ); ++} ++ ++/** A timer function that configures the cycle clock counter on current CPU. ++ The function \a mali_init_cpu_time_counters_on_all_cpus sets up this function ++ to trigger on all Cpus during module load. */ ++static void mali_init_cpu_clock_timer_func(unsigned long data) ++{ ++ int reset_counters, enable_divide_clock_counter_by_64; ++ int current_cpu = raw_smp_processor_id(); ++ unsigned int sample0; ++ unsigned int sample1; ++ ++ MALI_IGNORE(data); ++ ++ reset_counters= 1; ++ enable_divide_clock_counter_by_64 = 0; ++ mali_init_cpu_time_counters(reset_counters, enable_divide_clock_counter_by_64); ++ ++ sample0 = mali_get_cpu_cyclecount(); ++ sample1 = mali_get_cpu_cyclecount(); ++ ++ MALI_DEBUG_PRINT(3, ("Init Cpu %d cycle counter- First two samples: %08x %08x \n", current_cpu, sample0, sample1)); ++} ++ ++/** A timer functions for storing current time on all cpus. ++ Used for checking if the clocks have similar values or if they are drifting. */ ++static void mali_print_cpu_clock_timer_func(unsigned long data) ++{ ++ int current_cpu = raw_smp_processor_id(); ++ unsigned int sample0; ++ ++ MALI_IGNORE(data); ++ sample0 = mali_get_cpu_cyclecount(); ++ if ( current_cpu<8 ) { ++ mali_cpu_clock_last_value[current_cpu] = sample0; ++ } ++} ++ ++/** Init the performance registers on all CPUs to count clock cycles. ++ For init \a print_only should be 0. ++ If \a print_only is 1, it will intead print the current clock value of all CPUs.*/ ++void mali_init_cpu_time_counters_on_all_cpus(int print_only) ++{ ++ int i = 0; ++ int cpu_number; ++ int jiffies_trigger; ++ int jiffies_wait; ++ ++ jiffies_wait = 2; ++ jiffies_trigger = jiffies + jiffies_wait; ++ ++ for ( i=0 ; i < 8 ; i++ ) { ++ init_timer(&mali_init_cpu_clock_timers[i]); ++ if (print_only) mali_init_cpu_clock_timers[i].function = mali_print_cpu_clock_timer_func; ++ else mali_init_cpu_clock_timers[i].function = mali_init_cpu_clock_timer_func; ++ mali_init_cpu_clock_timers[i].expires = jiffies_trigger ; ++ } ++ cpu_number = cpumask_first(cpu_online_mask); ++ for ( i=0 ; i < 8 ; i++ ) { ++ int next_cpu; ++ add_timer_on(&mali_init_cpu_clock_timers[i], cpu_number); ++ next_cpu = cpumask_next(cpu_number, cpu_online_mask); ++ if (next_cpu >= nr_cpu_ids) break; ++ cpu_number = next_cpu; ++ } ++ ++ while (jiffies_wait) jiffies_wait= schedule_timeout_uninterruptible(jiffies_wait); ++ ++ for ( i=0 ; i < 8 ; i++ ) { ++ del_timer_sync(&mali_init_cpu_clock_timers[i]); ++ } ++ ++ if (print_only) { ++ if ( (0==mali_cpu_clock_last_value[2]) && (0==mali_cpu_clock_last_value[3]) ) { ++ /* Diff can be printed if we want to check if the clocks are in sync ++ int diff = mali_cpu_clock_last_value[0] - mali_cpu_clock_last_value[1];*/ ++ MALI_DEBUG_PRINT(2, ("CPU cycle counters readout all: %08x %08x\n", mali_cpu_clock_last_value[0], mali_cpu_clock_last_value[1])); ++ } else { ++ MALI_DEBUG_PRINT(2, ("CPU cycle counters readout all: %08x %08x %08x %08x\n", mali_cpu_clock_last_value[0], mali_cpu_clock_last_value[1], mali_cpu_clock_last_value[2], mali_cpu_clock_last_value[3] )); ++ } ++ } ++} ++#endif ++ ++ ++int mali_module_init(void) ++{ ++ int err = 0; ++ ++ MALI_DEBUG_PRINT(2, ("Inserting Mali v%d device driver. \n",_MALI_API_VERSION)); ++ MALI_DEBUG_PRINT(2, ("Compiled: %s, time: %s.\n", __DATE__, __TIME__)); ++ MALI_DEBUG_PRINT(2, ("Driver revision: %s\n", SVN_REV_STRING)); ++ ++#if MALI_ENABLE_CPU_CYCLES ++ mali_init_cpu_time_counters_on_all_cpus(0); ++ MALI_DEBUG_PRINT(2, ("CPU cycle counter setup complete\n")); ++ /* Printing the current cpu counters */ ++ mali_init_cpu_time_counters_on_all_cpus(1); ++#endif ++ ++ /* Initialize module wide settings */ ++#if defined(MALI_FAKE_PLATFORM_DEVICE) ++ MALI_DEBUG_PRINT(2, ("mali_module_init() registering device\n")); ++ err = mali_platform_device_register(); ++ if (0 != err) { ++ return err; ++ } ++#endif ++ err = sun8i_mali_platform_device_register(); ++ if (0 != err) ++ { ++ return err; ++ } ++ ++ MALI_DEBUG_PRINT(2, ("mali_module_init() registering driver\n")); ++ ++ err = platform_driver_register(&mali_platform_driver); ++ ++ if (0 != err) { ++ MALI_DEBUG_PRINT(2, ("mali_module_init() Failed to register driver (%d)\n", err)); ++#if defined(MALI_FAKE_PLATFORM_DEVICE) ++ mali_platform_device_unregister(); ++#endif ++ mali_platform_device = NULL; ++ return err; ++ } ++ ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++ err = _mali_internal_profiling_init(mali_boot_profiling ? MALI_TRUE : MALI_FALSE); ++ if (0 != err) { ++ /* No biggie if we wheren't able to initialize the profiling */ ++ MALI_PRINT_ERROR(("Failed to initialize profiling, feature will be unavailable\n")); ++ } ++#endif ++ ++ MALI_PRINT(("Mali device driver loaded\n")); ++ ++ return 0; /* Success */ ++} ++ ++void mali_module_exit(void) ++{ ++ MALI_DEBUG_PRINT(2, ("Unloading Mali v%d device driver.\n",_MALI_API_VERSION)); ++ ++ MALI_DEBUG_PRINT(2, ("mali_module_exit() unregistering driver\n")); ++ ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++ _mali_internal_profiling_term(); ++#endif ++ ++ platform_driver_unregister(&mali_platform_driver); ++ ++#if defined(MALI_FAKE_PLATFORM_DEVICE) ++ MALI_DEBUG_PRINT(2, ("mali_module_exit() unregistering device\n")); ++ mali_platform_device_unregister(); ++#endif ++ ++ MALI_PRINT(("Mali device driver unloaded\n")); ++} ++ ++static int mali_probe(struct platform_device *pdev) ++{ ++ int err; ++ ++ MALI_DEBUG_PRINT(2, ("mali_probe(): Called for platform device %s\n", pdev->name)); ++ ++ if (NULL != mali_platform_device) { ++ /* Already connected to a device, return error */ ++ MALI_PRINT_ERROR(("mali_probe(): The Mali driver is already connected with a Mali device.")); ++ return -EEXIST; ++ } ++ ++ mali_platform_device = pdev; ++ ++ sysfs_create_group(&mali_platform_device->dev.kobj, &gpu_attribute_group); ++ ++ if (_MALI_OSK_ERR_OK == _mali_osk_wq_init()) { ++ /* Initialize the Mali GPU HW specified by pdev */ ++ if (_MALI_OSK_ERR_OK == mali_initialize_subsystems()) { ++ /* Register a misc device (so we are accessible from user space) */ ++ err = mali_miscdevice_register(pdev); ++ if (0 == err) { ++ /* Setup sysfs entries */ ++ err = mali_sysfs_register(mali_dev_name); ++ if (0 == err) { ++ MALI_DEBUG_PRINT(2, ("mali_probe(): Successfully initialized driver for platform device %s\n", pdev->name)); ++ return 0; ++ } else { ++ MALI_PRINT_ERROR(("mali_probe(): failed to register sysfs entries")); ++ } ++ mali_miscdevice_unregister(); ++ } else { ++ MALI_PRINT_ERROR(("mali_probe(): failed to register Mali misc device.")); ++ } ++ mali_terminate_subsystems(); ++ } else { ++ MALI_PRINT_ERROR(("mali_probe(): Failed to initialize Mali device driver.")); ++ } ++ _mali_osk_wq_term(); ++ } ++ ++ mali_platform_device = NULL; ++ return -EFAULT; ++} ++ ++static int mali_remove(struct platform_device *pdev) ++{ ++ MALI_DEBUG_PRINT(2, ("mali_remove() called for platform device %s\n", pdev->name)); ++ mali_sysfs_unregister(); ++ mali_miscdevice_unregister(); ++ mali_terminate_subsystems(); ++ _mali_osk_wq_term(); ++ mali_platform_device = NULL; ++ return 0; ++} ++ ++static int mali_miscdevice_register(struct platform_device *pdev) ++{ ++ int err; ++ ++ mali_miscdevice.minor = MISC_DYNAMIC_MINOR; ++ mali_miscdevice.name = mali_dev_name; ++ mali_miscdevice.fops = &mali_fops; ++ mali_miscdevice.parent = get_device(&pdev->dev); ++ ++ err = misc_register(&mali_miscdevice); ++ if (0 != err) { ++ MALI_PRINT_ERROR(("Failed to register misc device, misc_register() returned %d\n", err)); ++ } ++ ++ return err; ++} ++ ++static void mali_miscdevice_unregister(void) ++{ ++ misc_deregister(&mali_miscdevice); ++} ++ ++static int mali_driver_suspend_scheduler(struct device *dev) ++{ ++ mali_pm_os_suspend(); ++ disable_gpu_clk(); ++ return 0; ++} ++ ++static int mali_driver_resume_scheduler(struct device *dev) ++{ ++ enable_gpu_clk(); ++ mali_pm_os_resume(); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_RUNTIME ++static int mali_driver_runtime_suspend(struct device *dev) ++{ ++ mali_pm_runtime_suspend(); ++ disable_gpu_clk(); ++ return 0; ++} ++ ++static int mali_driver_runtime_resume(struct device *dev) ++{ ++ enable_gpu_clk(); ++ mali_pm_runtime_resume(); ++ return 0; ++} ++ ++static int mali_driver_runtime_idle(struct device *dev) ++{ ++ /* Nothing to do */ ++ return 0; ++} ++#endif ++ ++static int mali_open(struct inode *inode, struct file *filp) ++{ ++ struct mali_session_data * session_data; ++ _mali_osk_errcode_t err; ++ ++ /* input validation */ ++ if (mali_miscdevice.minor != iminor(inode)) { ++ MALI_PRINT_ERROR(("mali_open() Minor does not match\n")); ++ return -ENODEV; ++ } ++ ++ /* allocated struct to track this session */ ++ err = _mali_ukk_open((void **)&session_data); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ /* initialize file pointer */ ++ filp->f_pos = 0; ++ ++ /* link in our session data */ ++ filp->private_data = (void*)session_data; ++ ++ return 0; ++} ++ ++static int mali_release(struct inode *inode, struct file *filp) ++{ ++ _mali_osk_errcode_t err; ++ ++ /* input validation */ ++ if (mali_miscdevice.minor != iminor(inode)) { ++ MALI_PRINT_ERROR(("mali_release() Minor does not match\n")); ++ return -ENODEV; ++ } ++ ++ err = _mali_ukk_close((void **)&filp->private_data); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ return 0; ++} ++ ++int map_errcode( _mali_osk_errcode_t err ) ++{ ++ switch(err) { ++ case _MALI_OSK_ERR_OK : ++ return 0; ++ case _MALI_OSK_ERR_FAULT: ++ return -EFAULT; ++ case _MALI_OSK_ERR_INVALID_FUNC: ++ return -ENOTTY; ++ case _MALI_OSK_ERR_INVALID_ARGS: ++ return -EINVAL; ++ case _MALI_OSK_ERR_NOMEM: ++ return -ENOMEM; ++ case _MALI_OSK_ERR_TIMEOUT: ++ return -ETIMEDOUT; ++ case _MALI_OSK_ERR_RESTARTSYSCALL: ++ return -ERESTARTSYS; ++ case _MALI_OSK_ERR_ITEM_NOT_FOUND: ++ return -ENOENT; ++ default: ++ return -EFAULT; ++ } ++} ++ ++#ifdef HAVE_UNLOCKED_IOCTL ++static long mali_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++#else ++static int mali_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++#endif ++{ ++ int err; ++ struct mali_session_data *session_data; ++ ++#ifndef HAVE_UNLOCKED_IOCTL ++ /* inode not used */ ++ (void)inode; ++#endif ++ ++ MALI_DEBUG_PRINT(7, ("Ioctl received 0x%08X 0x%08lX\n", cmd, arg)); ++ ++ session_data = (struct mali_session_data *)filp->private_data; ++ if (NULL == session_data) { ++ MALI_DEBUG_PRINT(7, ("filp->private_data was NULL\n")); ++ return -ENOTTY; ++ } ++ ++ if (NULL == (void *)arg) { ++ MALI_DEBUG_PRINT(7, ("arg was NULL\n")); ++ return -ENOTTY; ++ } ++ ++ switch(cmd) { ++ case MALI_IOC_WAIT_FOR_NOTIFICATION: ++ err = wait_for_notification_wrapper(session_data, (_mali_uk_wait_for_notification_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GET_API_VERSION: ++ err = get_api_version_wrapper(session_data, (_mali_uk_get_api_version_s __user *)arg); ++ break; ++ ++ case MALI_IOC_POST_NOTIFICATION: ++ err = post_notification_wrapper(session_data, (_mali_uk_post_notification_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GET_USER_SETTINGS: ++ err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg); ++ break; ++ ++ case MALI_IOC_REQUEST_HIGH_PRIORITY: ++ err = request_high_priority_wrapper(session_data, (_mali_uk_request_high_priority_s __user *)arg); ++ break; ++ ++#if defined(CONFIG_MALI400_PROFILING) ++ case MALI_IOC_PROFILING_START: ++ err = profiling_start_wrapper(session_data, (_mali_uk_profiling_start_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_ADD_EVENT: ++ err = profiling_add_event_wrapper(session_data, (_mali_uk_profiling_add_event_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_STOP: ++ err = profiling_stop_wrapper(session_data, (_mali_uk_profiling_stop_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_GET_EVENT: ++ err = profiling_get_event_wrapper(session_data, (_mali_uk_profiling_get_event_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_CLEAR: ++ err = profiling_clear_wrapper(session_data, (_mali_uk_profiling_clear_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_GET_CONFIG: ++ /* Deprecated: still compatible with get_user_settings */ ++ err = get_user_settings_wrapper(session_data, (_mali_uk_get_user_settings_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: ++ err = profiling_report_sw_counters_wrapper(session_data, (_mali_uk_sw_counters_report_s __user *)arg); ++ break; ++ ++#else ++ ++ case MALI_IOC_PROFILING_START: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_ADD_EVENT: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_STOP: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_GET_EVENT: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_CLEAR: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_GET_CONFIG: /* FALL-THROUGH */ ++ case MALI_IOC_PROFILING_REPORT_SW_COUNTERS: /* FALL-THROUGH */ ++ MALI_DEBUG_PRINT(2, ("Profiling not supported\n")); ++ err = -ENOTTY; ++ break; ++ ++#endif ++ ++ case MALI_IOC_MEM_WRITE_SAFE: ++ err = mem_write_safe_wrapper(session_data, (_mali_uk_mem_write_safe_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_MAP_EXT: ++ err = mem_map_ext_wrapper(session_data, (_mali_uk_map_external_mem_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_UNMAP_EXT: ++ err = mem_unmap_ext_wrapper(session_data, (_mali_uk_unmap_external_mem_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_QUERY_MMU_PAGE_TABLE_DUMP_SIZE: ++ err = mem_query_mmu_page_table_dump_size_wrapper(session_data, (_mali_uk_query_mmu_page_table_dump_size_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_DUMP_MMU_PAGE_TABLE: ++ err = mem_dump_mmu_page_table_wrapper(session_data, (_mali_uk_dump_mmu_page_table_s __user *)arg); ++ break; ++ ++#if defined(CONFIG_MALI400_UMP) ++ ++ case MALI_IOC_MEM_ATTACH_UMP: ++ err = mem_attach_ump_wrapper(session_data, (_mali_uk_attach_ump_mem_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_RELEASE_UMP: ++ err = mem_release_ump_wrapper(session_data, (_mali_uk_release_ump_mem_s __user *)arg); ++ break; ++ ++#else ++ ++ case MALI_IOC_MEM_ATTACH_UMP: ++ case MALI_IOC_MEM_RELEASE_UMP: /* FALL-THROUGH */ ++ MALI_DEBUG_PRINT(2, ("UMP not supported\n")); ++ err = -ENOTTY; ++ break; ++#endif ++ ++#ifdef CONFIG_DMA_SHARED_BUFFER ++ case MALI_IOC_MEM_ATTACH_DMA_BUF: ++ err = mali_attach_dma_buf(session_data, (_mali_uk_attach_dma_buf_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_RELEASE_DMA_BUF: ++ err = mali_release_dma_buf(session_data, (_mali_uk_release_dma_buf_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_DMA_BUF_GET_SIZE: ++ err = mali_dma_buf_get_size(session_data, (_mali_uk_dma_buf_get_size_s __user *)arg); ++ break; ++#else ++ ++ case MALI_IOC_MEM_ATTACH_DMA_BUF: /* FALL-THROUGH */ ++ case MALI_IOC_MEM_RELEASE_DMA_BUF: /* FALL-THROUGH */ ++ case MALI_IOC_MEM_DMA_BUF_GET_SIZE: /* FALL-THROUGH */ ++ MALI_DEBUG_PRINT(2, ("DMA-BUF not supported\n")); ++ err = -ENOTTY; ++ break; ++#endif ++ ++ case MALI_IOC_PP_START_JOB: ++ err = pp_start_job_wrapper(session_data, (_mali_uk_pp_start_job_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PP_AND_GP_START_JOB: ++ err = pp_and_gp_start_job_wrapper(session_data, (_mali_uk_pp_and_gp_start_job_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PP_NUMBER_OF_CORES_GET: ++ err = pp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_pp_number_of_cores_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PP_CORE_VERSION_GET: ++ err = pp_get_core_version_wrapper(session_data, (_mali_uk_get_pp_core_version_s __user *)arg); ++ break; ++ ++ case MALI_IOC_PP_DISABLE_WB: ++ err = pp_disable_wb_wrapper(session_data, (_mali_uk_pp_disable_wb_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GP2_START_JOB: ++ err = gp_start_job_wrapper(session_data, (_mali_uk_gp_start_job_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GP2_NUMBER_OF_CORES_GET: ++ err = gp_get_number_of_cores_wrapper(session_data, (_mali_uk_get_gp_number_of_cores_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GP2_CORE_VERSION_GET: ++ err = gp_get_core_version_wrapper(session_data, (_mali_uk_get_gp_core_version_s __user *)arg); ++ break; ++ ++ case MALI_IOC_GP2_SUSPEND_RESPONSE: ++ err = gp_suspend_response_wrapper(session_data, (_mali_uk_gp_suspend_response_s __user *)arg); ++ break; ++ ++ case MALI_IOC_VSYNC_EVENT_REPORT: ++ err = vsync_event_report_wrapper(session_data, (_mali_uk_vsync_event_report_s __user *)arg); ++ break; ++ ++ case MALI_IOC_TIMELINE_GET_LATEST_POINT: ++ err = timeline_get_latest_point_wrapper(session_data, (_mali_uk_timeline_get_latest_point_s __user *)arg); ++ break; ++ case MALI_IOC_TIMELINE_WAIT: ++ err = timeline_wait_wrapper(session_data, (_mali_uk_timeline_wait_s __user *)arg); ++ break; ++ case MALI_IOC_TIMELINE_CREATE_SYNC_FENCE: ++ err = timeline_create_sync_fence_wrapper(session_data, (_mali_uk_timeline_create_sync_fence_s __user *)arg); ++ break; ++ case MALI_IOC_SOFT_JOB_START: ++ err = soft_job_start_wrapper(session_data, (_mali_uk_soft_job_start_s __user *)arg); ++ break; ++ case MALI_IOC_SOFT_JOB_SIGNAL: ++ err = soft_job_signal_wrapper(session_data, (_mali_uk_soft_job_signal_s __user *)arg); ++ break; ++ ++ case MALI_IOC_MEM_INIT: /* Fallthrough */ ++ case MALI_IOC_MEM_TERM: /* Fallthrough */ ++ MALI_DEBUG_PRINT(2, ("Deprecated ioctls called\n")); ++ err = -ENOTTY; ++ break; ++ ++ case MALI_IOC_MEM_GET_BIG_BLOCK: /* Fallthrough */ ++ case MALI_IOC_MEM_FREE_BIG_BLOCK: ++ MALI_PRINT_ERROR(("Non-MMU mode is no longer supported.\n")); ++ err = -ENOTTY; ++ break; ++ ++ default: ++ MALI_DEBUG_PRINT(2, ("No handler for ioctl 0x%08X 0x%08lX\n", cmd, arg)); ++ err = -ENOTTY; ++ }; ++ ++ return err; ++} ++ ++ ++module_init(mali_module_init); ++module_exit(mali_module_exit); ++ ++MODULE_LICENSE(MALI_KERNEL_LINUX_LICENSE); ++MODULE_AUTHOR("ARM Ltd."); ++MODULE_VERSION(SVN_REV_STRING); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.h +new file mode 100644 +index 0000000..cf8e256 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_linux.h +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_LINUX_H__ ++#define __MALI_KERNEL_LINUX_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include /* character device definitions */ ++#include "mali_kernel_license.h" ++#include "mali_osk_types.h" ++ ++extern struct platform_device *mali_platform_device; ++ ++#if MALI_LICENSE_IS_GPL ++/* Defined in mali_osk_irq.h */ ++extern struct workqueue_struct * mali_wq_normal; ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_KERNEL_LINUX_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.c +new file mode 100644 +index 0000000..026e241 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.c +@@ -0,0 +1,1390 @@ ++/** ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++ ++/** ++ * @file mali_kernel_sysfs.c ++ * Implementation of some sysfs data exports ++ */ ++ ++#include ++#include ++#include ++#include ++#include "mali_kernel_license.h" ++#include "mali_kernel_common.h" ++#include "mali_ukk.h" ++ ++#if MALI_LICENSE_IS_GPL ++ ++#include ++#include ++#include ++#include ++#include ++#include "mali_kernel_sysfs.h" ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++#include ++#include "mali_osk_profiling.h" ++#endif ++ ++#include ++#include "mali_pm.h" ++#include "mali_pmu.h" ++#include "mali_group.h" ++#include "mali_gp.h" ++#include "mali_pp.h" ++#include "mali_l2_cache.h" ++#include "mali_hw_core.h" ++#include "mali_kernel_core.h" ++#include "mali_user_settings_db.h" ++#include "mali_profiling_internal.h" ++#include "mali_gp_job.h" ++#include "mali_pp_job.h" ++#include "mali_pp_scheduler.h" ++ ++#define PRIVATE_DATA_COUNTER_MAKE_GP(src) (src) ++#define PRIVATE_DATA_COUNTER_MAKE_PP(src) ((1 << 24) | src) ++#define PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(src, sub_job) ((1 << 24) | (1 << 16) | (sub_job << 8) | src) ++#define PRIVATE_DATA_COUNTER_IS_PP(a) ((((a) >> 24) & 0xFF) ? MALI_TRUE : MALI_FALSE) ++#define PRIVATE_DATA_COUNTER_GET_SRC(a) (a & 0xFF) ++#define PRIVATE_DATA_COUNTER_IS_SUB_JOB(a) ((((a) >> 16) & 0xFF) ? MALI_TRUE : MALI_FALSE) ++#define PRIVATE_DATA_COUNTER_GET_SUB_JOB(a) (((a) >> 8) & 0xFF) ++ ++#define POWER_BUFFER_SIZE 3 ++ ++static struct dentry *mali_debugfs_dir = NULL; ++ ++typedef enum { ++ _MALI_DEVICE_SUSPEND, ++ _MALI_DEVICE_RESUME, ++ _MALI_DEVICE_DVFS_PAUSE, ++ _MALI_DEVICE_DVFS_RESUME, ++ _MALI_MAX_EVENTS ++} _mali_device_debug_power_events; ++ ++static const char* const mali_power_events[_MALI_MAX_EVENTS] = { ++ [_MALI_DEVICE_SUSPEND] = "suspend", ++ [_MALI_DEVICE_RESUME] = "resume", ++ [_MALI_DEVICE_DVFS_PAUSE] = "dvfs_pause", ++ [_MALI_DEVICE_DVFS_RESUME] = "dvfs_resume", ++}; ++ ++static mali_bool power_always_on_enabled = MALI_FALSE; ++ ++static int open_copy_private_data(struct inode *inode, struct file *filp) ++{ ++ filp->private_data = inode->i_private; ++ return 0; ++} ++ ++static ssize_t group_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ int r; ++ char buffer[64]; ++ struct mali_group *group; ++ ++ group = (struct mali_group *)filp->private_data; ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ r = sprintf(buffer, "%u\n", mali_group_is_enabled(group) ? 1 : 0); ++ ++ return simple_read_from_buffer(buf, count, offp, buffer, r); ++} ++ ++static ssize_t group_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) ++{ ++ int r; ++ char buffer[64]; ++ unsigned long val; ++ struct mali_group *group; ++ ++ group = (struct mali_group *)filp->private_data; ++ MALI_DEBUG_ASSERT_POINTER(group); ++ ++ if (count >= sizeof(buffer)) { ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(&buffer[0], buf, count)) { ++ return -EFAULT; ++ } ++ buffer[count] = '\0'; ++ ++ r = strict_strtoul(&buffer[0], 10, &val); ++ if (0 != r) { ++ return -EINVAL; ++ } ++ ++ switch (val) { ++ case 1: ++ mali_group_enable(group); ++ break; ++ case 0: ++ mali_group_disable(group); ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ ++ *offp += count; ++ return count; ++} ++ ++static const struct file_operations group_enabled_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = group_enabled_read, ++ .write = group_enabled_write, ++}; ++ ++static ssize_t hw_core_base_addr_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ int r; ++ char buffer[64]; ++ struct mali_hw_core *hw_core; ++ ++ hw_core = (struct mali_hw_core *)filp->private_data; ++ MALI_DEBUG_ASSERT_POINTER(hw_core); ++ ++ r = sprintf(buffer, "0x%08X\n", hw_core->phys_addr); ++ ++ return simple_read_from_buffer(buf, count, offp, buffer, r); ++} ++ ++static const struct file_operations hw_core_base_addr_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = hw_core_base_addr_read, ++}; ++ ++static ssize_t profiling_counter_src_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ u32 is_pp = PRIVATE_DATA_COUNTER_IS_PP((u32)filp->private_data); ++ u32 src_id = PRIVATE_DATA_COUNTER_GET_SRC((u32)filp->private_data); ++ mali_bool is_sub_job = PRIVATE_DATA_COUNTER_IS_SUB_JOB((u32)filp->private_data); ++ u32 sub_job = PRIVATE_DATA_COUNTER_GET_SUB_JOB((u32)filp->private_data); ++ char buf[64]; ++ int r; ++ u32 val; ++ ++ if (MALI_TRUE == is_pp) { ++ /* PP counter */ ++ if (MALI_TRUE == is_sub_job) { ++ /* Get counter for a particular sub job */ ++ if (0 == src_id) { ++ val = mali_pp_job_get_pp_counter_sub_job_src0(sub_job); ++ } else { ++ val = mali_pp_job_get_pp_counter_sub_job_src1(sub_job); ++ } ++ } else { ++ /* Get default counter for all PP sub jobs */ ++ if (0 == src_id) { ++ val = mali_pp_job_get_pp_counter_global_src0(); ++ } else { ++ val = mali_pp_job_get_pp_counter_global_src1(); ++ } ++ } ++ } else { ++ /* GP counter */ ++ if (0 == src_id) { ++ val = mali_gp_job_get_gp_counter_src0(); ++ } else { ++ val = mali_gp_job_get_gp_counter_src1(); ++ } ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER == val) { ++ r = sprintf(buf, "-1\n"); ++ } else { ++ r = sprintf(buf, "%u\n", val); ++ } ++ ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static ssize_t profiling_counter_src_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ u32 is_pp = PRIVATE_DATA_COUNTER_IS_PP((u32)filp->private_data); ++ u32 src_id = PRIVATE_DATA_COUNTER_GET_SRC((u32)filp->private_data); ++ mali_bool is_sub_job = PRIVATE_DATA_COUNTER_IS_SUB_JOB((u32)filp->private_data); ++ u32 sub_job = PRIVATE_DATA_COUNTER_GET_SUB_JOB((u32)filp->private_data); ++ char buf[64]; ++ long val; ++ int ret; ++ ++ if (cnt >= sizeof(buf)) { ++ return -EINVAL; ++ } ++ ++ if (copy_from_user(&buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ ++ buf[cnt] = 0; ++ ++ ret = strict_strtol(buf, 10, &val); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (val < 0) { ++ /* any negative input will disable counter */ ++ val = MALI_HW_CORE_NO_COUNTER; ++ } ++ ++ if (MALI_TRUE == is_pp) { ++ /* PP counter */ ++ if (MALI_TRUE == is_sub_job) { ++ /* Set counter for a particular sub job */ ++ if (0 == src_id) { ++ mali_pp_job_set_pp_counter_sub_job_src0(sub_job, (u32)val); ++ } else { ++ mali_pp_job_set_pp_counter_sub_job_src1(sub_job, (u32)val); ++ } ++ } else { ++ /* Set default counter for all PP sub jobs */ ++ if (0 == src_id) { ++ mali_pp_job_set_pp_counter_global_src0((u32)val); ++ } else { ++ mali_pp_job_set_pp_counter_global_src1((u32)val); ++ } ++ } ++ } else { ++ /* GP counter */ ++ if (0 == src_id) { ++ mali_gp_job_set_gp_counter_src0((u32)val); ++ } else { ++ mali_gp_job_set_gp_counter_src1((u32)val); ++ } ++ } ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static const struct file_operations profiling_counter_src_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = profiling_counter_src_read, ++ .write = profiling_counter_src_write, ++}; ++ ++static ssize_t l2_l2x_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) ++{ ++ char buf[64]; ++ int r; ++ u32 val; ++ struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; ++ ++ if (0 == src_id) { ++ val = mali_l2_cache_core_get_counter_src0(l2_core); ++ } else { ++ val = mali_l2_cache_core_get_counter_src1(l2_core); ++ } ++ ++ if (MALI_HW_CORE_NO_COUNTER == val) { ++ r = sprintf(buf, "-1\n"); ++ } else { ++ r = sprintf(buf, "%u\n", val); ++ } ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static ssize_t l2_l2x_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) ++{ ++ struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data; ++ char buf[64]; ++ long val; ++ int ret; ++ ++ if (cnt >= sizeof(buf)) { ++ return -EINVAL; ++ } ++ ++ if (copy_from_user(&buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ ++ buf[cnt] = 0; ++ ++ ret = strict_strtol(buf, 10, &val); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (val < 0) { ++ /* any negative input will disable counter */ ++ val = MALI_HW_CORE_NO_COUNTER; ++ } ++ ++ if (0 == src_id) { ++ mali_l2_cache_core_set_counter_src0(l2_core, (u32)val); ++ } else { ++ mali_l2_cache_core_set_counter_src1(l2_core, (u32)val); ++ } ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static ssize_t l2_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id) ++{ ++ char buf[64]; ++ long val; ++ int ret; ++ u32 l2_id; ++ struct mali_l2_cache_core *l2_cache; ++ ++ if (cnt >= sizeof(buf)) { ++ return -EINVAL; ++ } ++ ++ if (copy_from_user(&buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ ++ buf[cnt] = 0; ++ ++ ret = strict_strtol(buf, 10, &val); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (val < 0) { ++ /* any negative input will disable counter */ ++ val = MALI_HW_CORE_NO_COUNTER; ++ } ++ ++ l2_id = 0; ++ l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); ++ while (NULL != l2_cache) { ++ if (0 == src_id) { ++ mali_l2_cache_core_set_counter_src0(l2_cache, (u32)val); ++ } else { ++ mali_l2_cache_core_set_counter_src1(l2_cache, (u32)val); ++ } ++ ++ /* try next L2 */ ++ l2_id++; ++ l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); ++ } ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static ssize_t l2_l2x_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 0); ++} ++ ++static ssize_t l2_l2x_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 1); ++} ++ ++static ssize_t l2_l2x_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 0); ++} ++ ++static ssize_t l2_l2x_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 1); ++} ++ ++static ssize_t l2_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0); ++} ++ ++static ssize_t l2_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1); ++} ++ ++static const struct file_operations l2_l2x_counter_src0_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = l2_l2x_counter_src0_read, ++ .write = l2_l2x_counter_src0_write, ++}; ++ ++static const struct file_operations l2_l2x_counter_src1_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = l2_l2x_counter_src1_read, ++ .write = l2_l2x_counter_src1_write, ++}; ++ ++static const struct file_operations l2_all_counter_src0_fops = { ++ .owner = THIS_MODULE, ++ .write = l2_all_counter_src0_write, ++}; ++ ++static const struct file_operations l2_all_counter_src1_fops = { ++ .owner = THIS_MODULE, ++ .write = l2_all_counter_src1_write, ++}; ++ ++static ssize_t power_always_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ unsigned long val; ++ int ret; ++ char buf[32]; ++ ++ cnt = min(cnt, sizeof(buf) - 1); ++ if (copy_from_user(buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ buf[cnt] = '\0'; ++ ++ ret = strict_strtoul(buf, 10, &val); ++ if (0 != ret) { ++ return ret; ++ } ++ ++ /* Update setting (not exactly thread safe) */ ++ if (1 == val && MALI_FALSE == power_always_on_enabled) { ++ power_always_on_enabled = MALI_TRUE; ++ _mali_osk_pm_dev_ref_add(); ++ } else if (0 == val && MALI_TRUE == power_always_on_enabled) { ++ power_always_on_enabled = MALI_FALSE; ++ _mali_osk_pm_dev_ref_dec(); ++ } ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static ssize_t power_always_on_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ if (MALI_TRUE == power_always_on_enabled) { ++ return simple_read_from_buffer(ubuf, cnt, ppos, "1\n", 2); ++ } else { ++ return simple_read_from_buffer(ubuf, cnt, ppos, "0\n", 2); ++ } ++} ++ ++static const struct file_operations power_always_on_fops = { ++ .owner = THIS_MODULE, ++ .read = power_always_on_read, ++ .write = power_always_on_write, ++}; ++ ++static ssize_t power_power_events_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ ++ if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_SUSPEND],strlen(mali_power_events[_MALI_DEVICE_SUSPEND]))) { ++ mali_pm_os_suspend(); ++ ++ } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_RESUME],strlen(mali_power_events[_MALI_DEVICE_RESUME]))) { ++ mali_pm_os_resume(); ++ } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_PAUSE],strlen(mali_power_events[_MALI_DEVICE_DVFS_PAUSE]))) { ++ mali_dev_pause(); ++ } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_RESUME],strlen(mali_power_events[_MALI_DEVICE_DVFS_RESUME]))) { ++ mali_dev_resume(); ++ } ++ *ppos += cnt; ++ return cnt; ++} ++ ++static loff_t power_power_events_seek(struct file *file, loff_t offset, int orig) ++{ ++ file->f_pos = offset; ++ return 0; ++} ++ ++static const struct file_operations power_power_events_fops = { ++ .owner = THIS_MODULE, ++ .write = power_power_events_write, ++ .llseek = power_power_events_seek, ++}; ++ ++#if MALI_STATE_TRACKING ++static int mali_seq_internal_state_show(struct seq_file *seq_file, void *v) ++{ ++ u32 len = 0; ++ u32 size; ++ char *buf; ++ ++ size = seq_get_buf(seq_file, &buf); ++ ++ if(!size) { ++ return -ENOMEM; ++ } ++ ++ /* Create the internal state dump. */ ++ len = snprintf(buf+len, size-len, "Mali device driver %s\n", SVN_REV_STRING); ++ len += snprintf(buf+len, size-len, "License: %s\n\n", MALI_KERNEL_LINUX_LICENSE); ++ ++ len += _mali_kernel_core_dump_state(buf + len, size - len); ++ ++ seq_commit(seq_file, len); ++ ++ return 0; ++} ++ ++static int mali_seq_internal_state_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mali_seq_internal_state_show, NULL); ++} ++ ++static const struct file_operations mali_seq_internal_state_fops = { ++ .owner = THIS_MODULE, ++ .open = mali_seq_internal_state_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++#endif /* MALI_STATE_TRACKING */ ++ ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++static ssize_t profiling_record_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ int r; ++ ++ r = sprintf(buf, "%u\n", _mali_internal_profiling_is_recording() ? 1 : 0); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ unsigned long val; ++ int ret; ++ ++ if (cnt >= sizeof(buf)) { ++ return -EINVAL; ++ } ++ ++ if (copy_from_user(&buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ ++ buf[cnt] = 0; ++ ++ ret = strict_strtoul(buf, 10, &val); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ if (val != 0) { ++ u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* This can be made configurable at a later stage if we need to */ ++ ++ /* check if we are already recording */ ++ if (MALI_TRUE == _mali_internal_profiling_is_recording()) { ++ MALI_DEBUG_PRINT(3, ("Recording of profiling events already in progress\n")); ++ return -EFAULT; ++ } ++ ++ /* check if we need to clear out an old recording first */ ++ if (MALI_TRUE == _mali_internal_profiling_have_recording()) { ++ if (_MALI_OSK_ERR_OK != _mali_internal_profiling_clear()) { ++ MALI_DEBUG_PRINT(3, ("Failed to clear existing recording of profiling events\n")); ++ return -EFAULT; ++ } ++ } ++ ++ /* start recording profiling data */ ++ if (_MALI_OSK_ERR_OK != _mali_internal_profiling_start(&limit)) { ++ MALI_DEBUG_PRINT(3, ("Failed to start recording of profiling events\n")); ++ return -EFAULT; ++ } ++ ++ MALI_DEBUG_PRINT(3, ("Profiling recording started (max %u events)\n", limit)); ++ } else { ++ /* stop recording profiling data */ ++ u32 count = 0; ++ if (_MALI_OSK_ERR_OK != _mali_internal_profiling_stop(&count)) { ++ MALI_DEBUG_PRINT(2, ("Failed to stop recording of profiling events\n")); ++ return -EFAULT; ++ } ++ ++ MALI_DEBUG_PRINT(2, ("Profiling recording stopped (recorded %u events)\n", count)); ++ } ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static const struct file_operations profiling_record_fops = { ++ .owner = THIS_MODULE, ++ .read = profiling_record_read, ++ .write = profiling_record_write, ++}; ++ ++static void *profiling_events_start(struct seq_file *s, loff_t *pos) ++{ ++ loff_t *spos; ++ ++ /* check if we have data avaiable */ ++ if (MALI_TRUE != _mali_internal_profiling_have_recording()) { ++ return NULL; ++ } ++ ++ spos = kmalloc(sizeof(loff_t), GFP_KERNEL); ++ if (NULL == spos) { ++ return NULL; ++ } ++ ++ *spos = *pos; ++ return spos; ++} ++ ++static void *profiling_events_next(struct seq_file *s, void *v, loff_t *pos) ++{ ++ loff_t *spos = v; ++ ++ /* check if we have data avaiable */ ++ if (MALI_TRUE != _mali_internal_profiling_have_recording()) { ++ return NULL; ++ } ++ ++ /* check if the next entry actually is avaiable */ ++ if (_mali_internal_profiling_get_count() <= (u32)(*spos + 1)) { ++ return NULL; ++ } ++ ++ *pos = ++*spos; ++ return spos; ++} ++ ++static void profiling_events_stop(struct seq_file *s, void *v) ++{ ++ kfree(v); ++} ++ ++static int profiling_events_show(struct seq_file *seq_file, void *v) ++{ ++ loff_t *spos = v; ++ u32 index; ++ u64 timestamp; ++ u32 event_id; ++ u32 data[5]; ++ ++ index = (u32)*spos; ++ ++ /* Retrieve all events */ ++ if (_MALI_OSK_ERR_OK == _mali_internal_profiling_get_event(index, ×tamp, &event_id, data)) { ++ seq_printf(seq_file, "%llu %u %u %u %u %u %u\n", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]); ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static int profiling_events_show_human_readable(struct seq_file *seq_file, void *v) ++{ ++#define MALI_EVENT_ID_IS_HW(event_id) (((event_id & 0x00FF0000) >= MALI_PROFILING_EVENT_CHANNEL_GP0) && ((event_id & 0x00FF0000) <= MALI_PROFILING_EVENT_CHANNEL_PP7)) ++ ++ static u64 start_time = 0; ++ loff_t *spos = v; ++ u32 index; ++ u64 timestamp; ++ u32 event_id; ++ u32 data[5]; ++ ++ index = (u32)*spos; ++ ++ /* Retrieve all events */ ++ if (_MALI_OSK_ERR_OK == _mali_internal_profiling_get_event(index, ×tamp, &event_id, data)) { ++ seq_printf(seq_file, "%llu %u %u %u %u %u %u # ", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]); ++ ++ if (0 == index) { ++ start_time = timestamp; ++ } ++ ++ seq_printf(seq_file, "[%06u] ", index); ++ ++ switch(event_id & 0x0F000000) { ++ case MALI_PROFILING_EVENT_TYPE_SINGLE: ++ seq_printf(seq_file, "SINGLE | "); ++ break; ++ case MALI_PROFILING_EVENT_TYPE_START: ++ seq_printf(seq_file, "START | "); ++ break; ++ case MALI_PROFILING_EVENT_TYPE_STOP: ++ seq_printf(seq_file, "STOP | "); ++ break; ++ case MALI_PROFILING_EVENT_TYPE_SUSPEND: ++ seq_printf(seq_file, "SUSPEND | "); ++ break; ++ case MALI_PROFILING_EVENT_TYPE_RESUME: ++ seq_printf(seq_file, "RESUME | "); ++ break; ++ default: ++ seq_printf(seq_file, "0x%01X | ", (event_id & 0x0F000000) >> 24); ++ break; ++ } ++ ++ switch(event_id & 0x00FF0000) { ++ case MALI_PROFILING_EVENT_CHANNEL_SOFTWARE: ++ seq_printf(seq_file, "SW | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_GP0: ++ seq_printf(seq_file, "GP0 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP0: ++ seq_printf(seq_file, "PP0 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP1: ++ seq_printf(seq_file, "PP1 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP2: ++ seq_printf(seq_file, "PP2 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP3: ++ seq_printf(seq_file, "PP3 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP4: ++ seq_printf(seq_file, "PP4 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP5: ++ seq_printf(seq_file, "PP5 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP6: ++ seq_printf(seq_file, "PP6 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_PP7: ++ seq_printf(seq_file, "PP7 | "); ++ break; ++ case MALI_PROFILING_EVENT_CHANNEL_GPU: ++ seq_printf(seq_file, "GPU | "); ++ break; ++ default: ++ seq_printf(seq_file, "0x%02X | ", (event_id & 0x00FF0000) >> 16); ++ break; ++ } ++ ++ if (MALI_EVENT_ID_IS_HW(event_id)) { ++ if (((event_id & 0x0F000000) == MALI_PROFILING_EVENT_TYPE_START) || ((event_id & 0x0F000000) == MALI_PROFILING_EVENT_TYPE_STOP)) { ++ switch(event_id & 0x0000FFFF) { ++ case MALI_PROFILING_EVENT_REASON_START_STOP_HW_PHYSICAL: ++ seq_printf(seq_file, "PHYSICAL | "); ++ break; ++ case MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL: ++ seq_printf(seq_file, "VIRTUAL | "); ++ break; ++ default: ++ seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF); ++ break; ++ } ++ } else { ++ seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF); ++ } ++ } else { ++ seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF); ++ } ++ ++ seq_printf(seq_file, "T0 + 0x%016llX\n", timestamp - start_time); ++ ++ return 0; ++ } ++ ++ return 0; ++} ++ ++static const struct seq_operations profiling_events_seq_ops = { ++ .start = profiling_events_start, ++ .next = profiling_events_next, ++ .stop = profiling_events_stop, ++ .show = profiling_events_show ++}; ++ ++static int profiling_events_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &profiling_events_seq_ops); ++} ++ ++static const struct file_operations profiling_events_fops = { ++ .owner = THIS_MODULE, ++ .open = profiling_events_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++static const struct seq_operations profiling_events_human_readable_seq_ops = { ++ .start = profiling_events_start, ++ .next = profiling_events_next, ++ .stop = profiling_events_stop, ++ .show = profiling_events_show_human_readable ++}; ++ ++static int profiling_events_human_readable_open(struct inode *inode, struct file *file) ++{ ++ return seq_open(file, &profiling_events_human_readable_seq_ops); ++} ++ ++static const struct file_operations profiling_events_human_readable_fops = { ++ .owner = THIS_MODULE, ++ .open = profiling_events_human_readable_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = seq_release, ++}; ++ ++#endif ++ ++static ssize_t memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 mem = _mali_ukk_report_memory_usage(); ++ ++ r = snprintf(buf, 64, "%u\n", mem); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static const struct file_operations memory_usage_fops = { ++ .owner = THIS_MODULE, ++ .read = memory_used_read, ++}; ++ ++static ssize_t utilization_gp_pp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 uval= _mali_ukk_utilization_gp_pp(); ++ ++ r = snprintf(buf, 64, "%u\n", uval); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static ssize_t utilization_gp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 uval= _mali_ukk_utilization_gp(); ++ ++ r = snprintf(buf, 64, "%u\n", uval); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static ssize_t utilization_pp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 uval= _mali_ukk_utilization_pp(); ++ ++ r = snprintf(buf, 64, "%u\n", uval); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++ ++static const struct file_operations utilization_gp_pp_fops = { ++ .owner = THIS_MODULE, ++ .read = utilization_gp_pp_read, ++}; ++ ++static const struct file_operations utilization_gp_fops = { ++ .owner = THIS_MODULE, ++ .read = utilization_gp_read, ++}; ++ ++static const struct file_operations utilization_pp_fops = { ++ .owner = THIS_MODULE, ++ .read = utilization_pp_read, ++}; ++ ++static ssize_t user_settings_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ unsigned long val; ++ int ret; ++ _mali_uk_user_setting_t setting; ++ char buf[32]; ++ ++ cnt = min(cnt, sizeof(buf) - 1); ++ if (copy_from_user(buf, ubuf, cnt)) { ++ return -EFAULT; ++ } ++ buf[cnt] = '\0'; ++ ++ ret = strict_strtoul(buf, 10, &val); ++ if (0 != ret) { ++ return ret; ++ } ++ ++ /* Update setting */ ++ setting = (_mali_uk_user_setting_t)(filp->private_data); ++ mali_set_user_setting(setting, val); ++ ++ *ppos += cnt; ++ return cnt; ++} ++ ++static ssize_t user_settings_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 value; ++ _mali_uk_user_setting_t setting; ++ ++ setting = (_mali_uk_user_setting_t)(filp->private_data); ++ value = mali_get_user_setting(setting); ++ ++ r = snprintf(buf, 64, "%u\n", value); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static const struct file_operations user_settings_fops = { ++ .owner = THIS_MODULE, ++ .open = open_copy_private_data, ++ .read = user_settings_read, ++ .write = user_settings_write, ++}; ++ ++static int mali_sysfs_user_settings_register(void) ++{ ++ struct dentry *mali_user_settings_dir = debugfs_create_dir("userspace_settings", mali_debugfs_dir); ++ ++ if (mali_user_settings_dir != NULL) { ++ int i; ++ for (i = 0; i < _MALI_UK_USER_SETTING_MAX; i++) { ++ debugfs_create_file(_mali_uk_user_setting_descriptions[i], 0600, mali_user_settings_dir, (void*)i, &user_settings_fops); ++ } ++ } ++ ++ return 0; ++} ++ ++static ssize_t pmu_power_down_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) ++{ ++ int ret; ++ char buffer[32]; ++ unsigned long val; ++ struct mali_pmu_core *pmu; ++ _mali_osk_errcode_t err; ++ ++ if (count >= sizeof(buffer)) { ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(&buffer[0], buf, count)) { ++ return -EFAULT; ++ } ++ buffer[count] = '\0'; ++ ++ ret = strict_strtoul(&buffer[0], 10, &val); ++ if (0 != ret) { ++ return -EINVAL; ++ } ++ ++ pmu = mali_pmu_get_global_pmu_core(); ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ ++ err = mali_pmu_power_down(pmu, val); ++ if (_MALI_OSK_ERR_OK != err) { ++ return -EINVAL; ++ } ++ ++ *offp += count; ++ return count; ++} ++ ++static ssize_t pmu_power_up_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) ++{ ++ int ret; ++ char buffer[32]; ++ unsigned long val; ++ struct mali_pmu_core *pmu; ++ _mali_osk_errcode_t err; ++ ++ if (count >= sizeof(buffer)) { ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(&buffer[0], buf, count)) { ++ return -EFAULT; ++ } ++ buffer[count] = '\0'; ++ ++ ret = strict_strtoul(&buffer[0], 10, &val); ++ if (0 != ret) { ++ return -EINVAL; ++ } ++ ++ pmu = mali_pmu_get_global_pmu_core(); ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ ++ err = mali_pmu_power_up(pmu, val); ++ if (_MALI_OSK_ERR_OK != err) { ++ return -EINVAL; ++ } ++ ++ *offp += count; ++ return count; ++} ++ ++static const struct file_operations pmu_power_down_fops = { ++ .owner = THIS_MODULE, ++ .write = pmu_power_down_write, ++}; ++ ++static const struct file_operations pmu_power_up_fops = { ++ .owner = THIS_MODULE, ++ .write = pmu_power_up_write, ++}; ++ ++static ssize_t pp_num_cores_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) ++{ ++ int ret; ++ char buffer[32]; ++ unsigned long val; ++ ++ if (count >= sizeof(buffer)) { ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(&buffer[0], buf, count)) { ++ return -EFAULT; ++ } ++ buffer[count] = '\0'; ++ ++ ret = strict_strtoul(&buffer[0], 10, &val); ++ if (0 != ret) { ++ return -EINVAL; ++ } ++ ++ ret = mali_pp_scheduler_set_perf_level(val, MALI_TRUE); /* override even if core scaling is disabled */ ++ if (ret) { ++ return ret; ++ } ++ ++ *offp += count; ++ return count; ++} ++ ++static ssize_t pp_num_cores_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ int r; ++ char buffer[64]; ++ ++ r = sprintf(buffer, "%u\n", mali_pp_scheduler_get_num_cores_enabled()); ++ ++ return simple_read_from_buffer(buf, count, offp, buffer, r); ++} ++ ++static const struct file_operations pp_num_cores_enabled_fops = { ++ .owner = THIS_MODULE, ++ .write = pp_num_cores_enabled_write, ++ .read = pp_num_cores_enabled_read, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t pp_num_cores_total_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ int r; ++ char buffer[64]; ++ ++ r = sprintf(buffer, "%u\n", mali_pp_scheduler_get_num_cores_total()); ++ ++ return simple_read_from_buffer(buf, count, offp, buffer, r); ++} ++ ++static const struct file_operations pp_num_cores_total_fops = { ++ .owner = THIS_MODULE, ++ .read = pp_num_cores_total_read, ++}; ++ ++static ssize_t pp_core_scaling_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp) ++{ ++ int ret; ++ char buffer[32]; ++ unsigned long val; ++ ++ if (count >= sizeof(buffer)) { ++ return -ENOMEM; ++ } ++ ++ if (copy_from_user(&buffer[0], buf, count)) { ++ return -EFAULT; ++ } ++ buffer[count] = '\0'; ++ ++ ret = strict_strtoul(&buffer[0], 10, &val); ++ if (0 != ret) { ++ return -EINVAL; ++ } ++ ++ switch (val) { ++ case 1: ++ mali_pp_scheduler_core_scaling_enable(); ++ break; ++ case 0: ++ mali_pp_scheduler_core_scaling_disable(); ++ break; ++ default: ++ return -EINVAL; ++ break; ++ } ++ ++ *offp += count; ++ return count; ++} ++ ++static ssize_t pp_core_scaling_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ return simple_read_from_buffer(buf, count, offp, mali_pp_scheduler_core_scaling_is_enabled() ? "1\n" : "0\n", 2); ++} ++static const struct file_operations pp_core_scaling_enabled_fops = { ++ .owner = THIS_MODULE, ++ .write = pp_core_scaling_enabled_write, ++ .read = pp_core_scaling_enabled_read, ++ .llseek = default_llseek, ++}; ++ ++static ssize_t version_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) ++{ ++ int r = 0; ++ char buffer[64]; ++ ++ switch (mali_kernel_core_get_product_id()) { ++ case _MALI_PRODUCT_ID_MALI200: ++ r = sprintf(buffer, "Mali-200\n"); ++ break; ++ case _MALI_PRODUCT_ID_MALI300: ++ r = sprintf(buffer, "Mali-300\n"); ++ break; ++ case _MALI_PRODUCT_ID_MALI400: ++ r = sprintf(buffer, "Mali-400 MP\n"); ++ break; ++ case _MALI_PRODUCT_ID_MALI450: ++ r = sprintf(buffer, "Mali-450 MP\n"); ++ break; ++ case _MALI_PRODUCT_ID_UNKNOWN: ++ return -EINVAL; ++ break; ++ }; ++ ++ return simple_read_from_buffer(buf, count, offp, buffer, r); ++} ++ ++static const struct file_operations version_fops = { ++ .owner = THIS_MODULE, ++ .read = version_read, ++}; ++ ++int mali_sysfs_register(const char *mali_dev_name) ++{ ++ mali_debugfs_dir = debugfs_create_dir(mali_dev_name, NULL); ++ if(ERR_PTR(-ENODEV) == mali_debugfs_dir) { ++ /* Debugfs not supported. */ ++ mali_debugfs_dir = NULL; ++ } else { ++ if(NULL != mali_debugfs_dir) { ++ /* Debugfs directory created successfully; create files now */ ++ struct dentry *mali_pmu_dir; ++ struct dentry *mali_power_dir; ++ struct dentry *mali_gp_dir; ++ struct dentry *mali_pp_dir; ++ struct dentry *mali_l2_dir; ++ struct dentry *mali_profiling_dir; ++ ++ debugfs_create_file("version", 0400, mali_debugfs_dir, NULL, &version_fops); ++ ++ mali_pmu_dir = debugfs_create_dir("pmu", mali_debugfs_dir); ++ if (NULL != mali_pmu_dir) { ++ debugfs_create_file("power_down", 0200, mali_pmu_dir, NULL, &pmu_power_down_fops); ++ debugfs_create_file("power_up", 0200, mali_pmu_dir, NULL, &pmu_power_up_fops); ++ } ++ ++ mali_power_dir = debugfs_create_dir("power", mali_debugfs_dir); ++ if (mali_power_dir != NULL) { ++ debugfs_create_file("always_on", 0600, mali_power_dir, NULL, &power_always_on_fops); ++ debugfs_create_file("power_events", 0200, mali_power_dir, NULL, &power_power_events_fops); ++ } ++ ++ mali_gp_dir = debugfs_create_dir("gp", mali_debugfs_dir); ++ if (mali_gp_dir != NULL) { ++ u32 num_groups; ++ int i; ++ ++ num_groups = mali_group_get_glob_num_groups(); ++ for (i = 0; i < num_groups; i++) { ++ struct mali_group *group = mali_group_get_glob_group(i); ++ ++ struct mali_gp_core *gp_core = mali_group_get_gp_core(group); ++ if (NULL != gp_core) { ++ struct dentry *mali_gp_gpx_dir; ++ mali_gp_gpx_dir = debugfs_create_dir("gp0", mali_gp_dir); ++ if (NULL != mali_gp_gpx_dir) { ++ debugfs_create_file("base_addr", 0400, mali_gp_gpx_dir, &gp_core->hw_core, &hw_core_base_addr_fops); ++ debugfs_create_file("enabled", 0600, mali_gp_gpx_dir, group, &group_enabled_fops); ++ } ++ break; /* no need to look for any other GP cores */ ++ } ++ ++ } ++ } ++ ++ mali_pp_dir = debugfs_create_dir("pp", mali_debugfs_dir); ++ if (mali_pp_dir != NULL) { ++ u32 num_groups; ++ int i; ++ ++ debugfs_create_file("num_cores_total", 0400, mali_pp_dir, NULL, &pp_num_cores_total_fops); ++ debugfs_create_file("num_cores_enabled", 0600, mali_pp_dir, NULL, &pp_num_cores_enabled_fops); ++ debugfs_create_file("core_scaling_enabled", 0600, mali_pp_dir, NULL, &pp_core_scaling_enabled_fops); ++ ++ num_groups = mali_group_get_glob_num_groups(); ++ for (i = 0; i < num_groups; i++) { ++ struct mali_group *group = mali_group_get_glob_group(i); ++ ++ struct mali_pp_core *pp_core = mali_group_get_pp_core(group); ++ if (NULL != pp_core) { ++ char buf[16]; ++ struct dentry *mali_pp_ppx_dir; ++ _mali_osk_snprintf(buf, sizeof(buf), "pp%u", mali_pp_core_get_id(pp_core)); ++ mali_pp_ppx_dir = debugfs_create_dir(buf, mali_pp_dir); ++ if (NULL != mali_pp_ppx_dir) { ++ debugfs_create_file("base_addr", 0400, mali_pp_ppx_dir, &pp_core->hw_core, &hw_core_base_addr_fops); ++ if (!mali_group_is_virtual(group)) { ++ debugfs_create_file("enabled", 0600, mali_pp_ppx_dir, group, &group_enabled_fops); ++ } ++ } ++ } ++ } ++ } ++ ++ mali_l2_dir = debugfs_create_dir("l2", mali_debugfs_dir); ++ if (mali_l2_dir != NULL) { ++ struct dentry *mali_l2_all_dir; ++ u32 l2_id; ++ struct mali_l2_cache_core *l2_cache; ++ ++ mali_l2_all_dir = debugfs_create_dir("all", mali_l2_dir); ++ if (mali_l2_all_dir != NULL) { ++ debugfs_create_file("counter_src0", 0200, mali_l2_all_dir, NULL, &l2_all_counter_src0_fops); ++ debugfs_create_file("counter_src1", 0200, mali_l2_all_dir, NULL, &l2_all_counter_src1_fops); ++ } ++ ++ l2_id = 0; ++ l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); ++ while (NULL != l2_cache) { ++ char buf[16]; ++ struct dentry *mali_l2_l2x_dir; ++ _mali_osk_snprintf(buf, sizeof(buf), "l2%u", l2_id); ++ mali_l2_l2x_dir = debugfs_create_dir(buf, mali_l2_dir); ++ if (NULL != mali_l2_l2x_dir) { ++ debugfs_create_file("counter_src0", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src0_fops); ++ debugfs_create_file("counter_src1", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src1_fops); ++ debugfs_create_file("base_addr", 0400, mali_l2_l2x_dir, &l2_cache->hw_core, &hw_core_base_addr_fops); ++ } ++ ++ /* try next L2 */ ++ l2_id++; ++ l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id); ++ } ++ } ++ ++ debugfs_create_file("memory_usage", 0400, mali_debugfs_dir, NULL, &memory_usage_fops); ++ ++ debugfs_create_file("utilization_gp_pp", 0400, mali_debugfs_dir, NULL, &utilization_gp_pp_fops); ++ debugfs_create_file("utilization_gp", 0400, mali_debugfs_dir, NULL, &utilization_gp_fops); ++ debugfs_create_file("utilization_pp", 0400, mali_debugfs_dir, NULL, &utilization_pp_fops); ++ ++ mali_profiling_dir = debugfs_create_dir("profiling", mali_debugfs_dir); ++ if (mali_profiling_dir != NULL) { ++ u32 max_sub_jobs; ++ int i; ++ struct dentry *mali_profiling_gp_dir; ++ struct dentry *mali_profiling_pp_dir; ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++ struct dentry *mali_profiling_proc_dir; ++#endif ++ /* ++ * Create directory where we can set GP HW counters. ++ */ ++ mali_profiling_gp_dir = debugfs_create_dir("gp", mali_profiling_dir); ++ if (mali_profiling_gp_dir != NULL) { ++ debugfs_create_file("counter_src0", 0600, mali_profiling_gp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_GP(0), &profiling_counter_src_fops); ++ debugfs_create_file("counter_src1", 0600, mali_profiling_gp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_GP(1), &profiling_counter_src_fops); ++ } ++ ++ /* ++ * Create directory where we can set PP HW counters. ++ * Possible override with specific HW counters for a particular sub job ++ * (Disable core scaling before using the override!) ++ */ ++ mali_profiling_pp_dir = debugfs_create_dir("pp", mali_profiling_dir); ++ if (mali_profiling_pp_dir != NULL) { ++ debugfs_create_file("counter_src0", 0600, mali_profiling_pp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP(0), &profiling_counter_src_fops); ++ debugfs_create_file("counter_src1", 0600, mali_profiling_pp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP(1), &profiling_counter_src_fops); ++ } ++ ++ max_sub_jobs = mali_pp_scheduler_get_num_cores_total(); ++ for (i = 0; i < max_sub_jobs; i++) { ++ char buf[16]; ++ struct dentry *mali_profiling_pp_x_dir; ++ _mali_osk_snprintf(buf, sizeof(buf), "%u", i); ++ mali_profiling_pp_x_dir = debugfs_create_dir(buf, mali_profiling_pp_dir); ++ if (NULL != mali_profiling_pp_x_dir) { ++ debugfs_create_file("counter_src0", 0600, mali_profiling_pp_x_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(0, i), &profiling_counter_src_fops); ++ debugfs_create_file("counter_src1", 0600, mali_profiling_pp_x_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(1, i), &profiling_counter_src_fops); ++ } ++ } ++ ++#if defined(CONFIG_MALI400_INTERNAL_PROFILING) ++ mali_profiling_proc_dir = debugfs_create_dir("proc", mali_profiling_dir); ++ if (mali_profiling_proc_dir != NULL) { ++ struct dentry *mali_profiling_proc_default_dir = debugfs_create_dir("default", mali_profiling_proc_dir); ++ if (mali_profiling_proc_default_dir != NULL) { ++ debugfs_create_file("enable", 0600, mali_profiling_proc_default_dir, (void*)_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, &user_settings_fops); ++ } ++ } ++ debugfs_create_file("record", 0600, mali_profiling_dir, NULL, &profiling_record_fops); ++ debugfs_create_file("events", 0400, mali_profiling_dir, NULL, &profiling_events_fops); ++ debugfs_create_file("events_human_readable", 0400, mali_profiling_dir, NULL, &profiling_events_human_readable_fops); ++#endif ++ } ++ ++#if MALI_STATE_TRACKING ++ debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops); ++#endif ++ ++ if (mali_sysfs_user_settings_register()) { ++ /* Failed to create the debugfs entries for the user settings DB. */ ++ MALI_DEBUG_PRINT(2, ("Failed to create user setting debugfs files. Ignoring...\n")); ++ } ++ } ++ } ++ ++ /* Success! */ ++ return 0; ++} ++ ++int mali_sysfs_unregister(void) ++{ ++ if(NULL != mali_debugfs_dir) { ++ debugfs_remove_recursive(mali_debugfs_dir); ++ } ++ return 0; ++} ++ ++#else /* MALI_LICENSE_IS_GPL */ ++ ++/* Dummy implementations for non-GPL */ ++ ++int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name) ++{ ++ return 0; ++} ++ ++int mali_sysfs_unregister(void) ++{ ++ return 0; ++} ++ ++#endif /* MALI_LICENSE_IS_GPL */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.h +new file mode 100644 +index 0000000..af1ddde +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_kernel_sysfs.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_KERNEL_SYSFS_H__ ++#define __MALI_KERNEL_SYSFS_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++ ++#define MALI_PROC_DIR "driver/mali" ++ ++int mali_sysfs_register(const char *mali_dev_name); ++int mali_sysfs_unregister(void); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_KERNEL_LINUX_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_linux_trace.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_linux_trace.h +new file mode 100644 +index 0000000..6c20250 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_linux_trace.h +@@ -0,0 +1,126 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#if !defined (MALI_LINUX_TRACE_H) || defined (TRACE_HEADER_MULTI_READ) ++#define MALI_LINUX_TRACE_H ++ ++#include ++ ++#include ++#include ++ ++#undef TRACE_SYSTEM ++#define TRACE_SYSTEM mali ++#define TRACE_SYSTEM_STRING __stringfy(TRACE_SYSTEM) ++ ++#define TRACE_INCLUDE_PATH . ++#define TRACE_INCLUDE_FILE mali_linux_trace ++ ++/** ++ * Define the tracepoint used to communicate the status of a GPU. Called ++ * when a GPU turns on or turns off. ++ * ++ * @param event_id The type of the event. This parameter is a bitfield ++ * encoding the type of the event. ++ * ++ * @param d0 First data parameter. ++ * @param d1 Second data parameter. ++ * @param d2 Third data parameter. ++ * @param d3 Fourth data parameter. ++ * @param d4 Fifth data parameter. ++ */ ++TRACE_EVENT(mali_timeline_event, ++ ++ TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, ++ unsigned int d2, unsigned int d3, unsigned int d4), ++ ++ TP_ARGS(event_id, d0, d1, d2, d3, d4), ++ ++ TP_STRUCT__entry( ++ __field(unsigned int, event_id) ++ __field(unsigned int, d0) ++ __field(unsigned int, d1) ++ __field(unsigned int, d2) ++ __field(unsigned int, d3) ++ __field(unsigned int, d4) ++ ), ++ ++ TP_fast_assign( ++ __entry->event_id = event_id; ++ __entry->d0 = d0; ++ __entry->d1 = d1; ++ __entry->d2 = d2; ++ __entry->d3 = d3; ++ __entry->d4 = d4; ++ ), ++ ++ TP_printk("event=%d", __entry->event_id) ++ ); ++ ++/** ++ * Define a tracepoint used to regsiter the value of a hardware counter. ++ * Hardware counters belonging to the vertex or fragment processor are ++ * reported via this tracepoint each frame, whilst L2 cache hardware ++ * counters are reported continuously. ++ * ++ * @param counter_id The counter ID. ++ * @param value The value of the counter. ++ */ ++TRACE_EVENT(mali_hw_counter, ++ ++ TP_PROTO(unsigned int counter_id, unsigned int value), ++ ++ TP_ARGS(counter_id, value), ++ ++ TP_STRUCT__entry( ++ __field(unsigned int, counter_id) ++ __field(unsigned int, value) ++ ), ++ ++ TP_fast_assign( ++ __entry->counter_id = counter_id; ++ ), ++ ++ TP_printk("event %d = %d", __entry->counter_id, __entry->value) ++ ); ++ ++/** ++ * Define a tracepoint used to send a bundle of software counters. ++ * ++ * @param counters The bundle of counters. ++ */ ++TRACE_EVENT(mali_sw_counters, ++ ++ TP_PROTO(pid_t pid, pid_t tid, void * surface_id, unsigned int * counters), ++ ++ TP_ARGS(pid, tid, surface_id, counters), ++ ++ TP_STRUCT__entry( ++ __field(pid_t, pid) ++ __field(pid_t, tid) ++ __field(void *, surface_id) ++ __field(unsigned int *, counters) ++ ), ++ ++ TP_fast_assign( ++ __entry->pid = pid; ++ __entry->tid = tid; ++ __entry->surface_id = surface_id; ++ __entry->counters = counters; ++ ), ++ ++ TP_printk("counters were %s", __entry->counters == NULL? "NULL" : "not NULL") ++ ); ++ ++#endif /* MALI_LINUX_TRACE_H */ ++ ++/* This part must exist outside the header guard. */ ++#include ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.c +new file mode 100644 +index 0000000..f0c4658 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.c +@@ -0,0 +1,353 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_kernel_linux.h" ++#include "mali_scheduler.h" ++#include "mali_kernel_descriptor_mapping.h" ++ ++#include "mali_memory.h" ++#include "mali_memory_dma_buf.h" ++#include "mali_memory_os_alloc.h" ++#include "mali_memory_block_alloc.h" ++ ++/* session->memory_lock must be held when calling this function */ ++static void mali_mem_release(mali_mem_allocation *descriptor) ++{ ++ MALI_DEBUG_ASSERT_POINTER(descriptor); ++ MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock); ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ switch (descriptor->type) { ++ case MALI_MEM_OS: ++ mali_mem_os_release(descriptor); ++ break; ++ case MALI_MEM_DMA_BUF: ++#if defined(CONFIG_DMA_SHARED_BUFFER) ++ mali_mem_dma_buf_release(descriptor); ++#endif ++ break; ++ case MALI_MEM_UMP: ++#if defined(CONFIG_MALI400_UMP) ++ mali_mem_ump_release(descriptor); ++#endif ++ break; ++ case MALI_MEM_EXTERNAL: ++ mali_mem_external_release(descriptor); ++ break; ++ case MALI_MEM_BLOCK: ++ mali_mem_block_release(descriptor); ++ break; ++ } ++} ++ ++static void mali_mem_vma_open(struct vm_area_struct * vma) ++{ ++ mali_mem_allocation *descriptor = (mali_mem_allocation*)vma->vm_private_data; ++ MALI_DEBUG_PRINT(4, ("Open called on vma %p\n", vma)); ++ ++ descriptor->cpu_mapping.ref++; ++ ++ return; ++} ++ ++static void mali_mem_vma_close(struct vm_area_struct *vma) ++{ ++ mali_mem_allocation *descriptor; ++ struct mali_session_data *session; ++ mali_mem_virt_cpu_mapping *mapping; ++ ++ MALI_DEBUG_PRINT(3, ("Close called on vma %p\n", vma)); ++ ++ descriptor = (mali_mem_allocation*)vma->vm_private_data; ++ BUG_ON(!descriptor); ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ mapping = &descriptor->cpu_mapping; ++ BUG_ON(0 == mapping->ref); ++ ++ mapping->ref--; ++ if (0 != mapping->ref) { ++ MALI_DEBUG_PRINT(3, ("Ignoring this close, %d references still exists\n", mapping->ref)); ++ return; ++ } ++ ++ session = descriptor->session; ++ ++ mali_descriptor_mapping_free(session->descriptor_mapping, descriptor->id); ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_release(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ mali_mem_descriptor_destroy(descriptor); ++} ++ ++static int mali_kernel_memory_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf) ++{ ++ void __user * address; ++ mali_mem_allocation *descriptor; ++ ++ address = vmf->virtual_address; ++ descriptor = (mali_mem_allocation *)vma->vm_private_data; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ /* ++ * We always fail the call since all memory is pre-faulted when assigned to the process. ++ * Only the Mali cores can use page faults to extend buffers. ++ */ ++ ++ MALI_DEBUG_PRINT(1, ("Page-fault in Mali memory region caused by the CPU.\n")); ++ MALI_DEBUG_PRINT(1, ("Tried to access %p (process local virtual address) which is not currently mapped to any Mali memory.\n", (void*)address)); ++ ++ MALI_IGNORE(address); ++ MALI_IGNORE(descriptor); ++ ++ return VM_FAULT_SIGBUS; ++} ++ ++struct vm_operations_struct mali_kernel_vm_ops = { ++ .open = mali_mem_vma_open, ++ .close = mali_mem_vma_close, ++ .fault = mali_kernel_memory_cpu_page_fault_handler ++}; ++ ++/** @note munmap handler is done by vma close handler */ ++int mali_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct mali_session_data *session; ++ mali_mem_allocation *descriptor; ++ u32 size = vma->vm_end - vma->vm_start; ++ u32 mali_addr = vma->vm_pgoff << PAGE_SHIFT; ++ ++ session = (struct mali_session_data *)filp->private_data; ++ if (NULL == session) { ++ MALI_PRINT_ERROR(("mmap called without any session data available\n")); ++ return -EFAULT; ++ } ++ ++ MALI_DEBUG_PRINT(4, ("MMap() handler: start=0x%08X, phys=0x%08X, size=0x%08X vma->flags 0x%08x\n", ++ (unsigned int)vma->vm_start, (unsigned int)(vma->vm_pgoff << PAGE_SHIFT), ++ (unsigned int)(vma->vm_end - vma->vm_start), vma->vm_flags)); ++ ++ /* Set some bits which indicate that, the memory is IO memory, meaning ++ * that no paging is to be performed and the memory should not be ++ * included in crash dumps. And that the memory is reserved, meaning ++ * that it's present and can never be paged out (see also previous ++ * entry) ++ */ ++ vma->vm_flags |= VM_IO; ++ vma->vm_flags |= VM_DONTCOPY; ++ vma->vm_flags |= VM_PFNMAP; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) ++ vma->vm_flags |= VM_RESERVED; ++#else ++ vma->vm_flags |= VM_DONTDUMP; ++ vma->vm_flags |= VM_DONTEXPAND; ++#endif ++ ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ vma->vm_ops = &mali_kernel_vm_ops; /* Operations used on any memory system */ ++ ++ descriptor = mali_mem_block_alloc(mali_addr, size, vma, session); ++ if (NULL == descriptor) { ++ descriptor = mali_mem_os_alloc(mali_addr, size, vma, session); ++ if (NULL == descriptor) { ++ MALI_DEBUG_PRINT(3, ("MMAP failed\n")); ++ return -ENOMEM; ++ } ++ } ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ vma->vm_private_data = (void*)descriptor; ++ ++ /* Put on descriptor map */ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &descriptor->id)) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_os_release(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++ ++/* Prepare memory descriptor */ ++mali_mem_allocation *mali_mem_descriptor_create(struct mali_session_data *session, mali_mem_type type) ++{ ++ mali_mem_allocation *descriptor; ++ ++ descriptor = (mali_mem_allocation*)kzalloc(sizeof(mali_mem_allocation), GFP_KERNEL); ++ if (NULL == descriptor) { ++ MALI_DEBUG_PRINT(3,("mali_ukk_mem_mmap: descriptor was NULL\n")); ++ return NULL; ++ } ++ ++ MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_VALID_MAGIC); ++ ++ descriptor->flags = 0; ++ descriptor->type = type; ++ descriptor->session = session; ++ ++ return descriptor; ++} ++ ++void mali_mem_descriptor_destroy(mali_mem_allocation *descriptor) ++{ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ MALI_DEBUG_CODE(descriptor->magic = MALI_MEM_ALLOCATION_FREED_MAGIC); ++ ++ kfree(descriptor); ++} ++ ++_mali_osk_errcode_t mali_mem_mali_map_prepare(mali_mem_allocation *descriptor) ++{ ++ u32 size = descriptor->size; ++ struct mali_session_data *session = descriptor->session; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ /* Map dma-buf into this session's page tables */ ++ ++ if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) { ++ size += MALI_MMU_PAGE_SIZE; ++ } ++ ++ return mali_mmu_pagedir_map(session->page_directory, descriptor->mali_mapping.addr, size); ++} ++ ++void mali_mem_mali_map_free(mali_mem_allocation *descriptor) ++{ ++ u32 size = descriptor->size; ++ struct mali_session_data *session = descriptor->session; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_ALLOCATION_VALID_MAGIC == descriptor->magic); ++ ++ if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) { ++ size += MALI_MMU_PAGE_SIZE; ++ } ++ ++ /* Umap and flush L2 */ ++ mali_mmu_pagedir_unmap(session->page_directory, descriptor->mali_mapping.addr, descriptor->size); ++ ++ mali_scheduler_zap_all_active(session); ++} ++ ++u32 _mali_ukk_report_memory_usage(void) ++{ ++ u32 sum = 0; ++ ++ sum += mali_mem_block_allocator_stat(); ++ sum += mali_mem_os_stat(); ++ ++ return sum; ++} ++ ++/** ++ * Per-session memory descriptor mapping table sizes ++ */ ++#define MALI_MEM_DESCRIPTORS_INIT 64 ++#define MALI_MEM_DESCRIPTORS_MAX 65536 ++ ++_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data * session_data) ++{ ++ MALI_DEBUG_PRINT(5, ("Memory session begin\n")); ++ ++ /* Create descriptor mapping table */ ++ session_data->descriptor_mapping = mali_descriptor_mapping_create(MALI_MEM_DESCRIPTORS_INIT, MALI_MEM_DESCRIPTORS_MAX); ++ ++ if (NULL == session_data->descriptor_mapping) { ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ session_data->memory_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED, ++ _MALI_OSK_LOCK_ORDER_MEM_SESSION); ++ ++ if (NULL == session_data->memory_lock) { ++ mali_descriptor_mapping_destroy(session_data->descriptor_mapping); ++ _mali_osk_free(session_data); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ MALI_DEBUG_PRINT(5, ("MMU session begin: success\n")); ++ MALI_SUCCESS; ++} ++ ++/** @brief Callback function that releases memory ++ * ++ * session->memory_lock must be held when calling this function. ++ */ ++static void descriptor_table_cleanup_callback(int descriptor_id, void* map_target) ++{ ++ mali_mem_allocation *descriptor; ++ ++ descriptor = (mali_mem_allocation*)map_target; ++ ++ MALI_DEBUG_ASSERT_LOCK_HELD(descriptor->session->memory_lock); ++ ++ MALI_DEBUG_PRINT(3, ("Cleanup of descriptor %d mapping to 0x%x in descriptor table\n", descriptor_id, map_target)); ++ MALI_DEBUG_ASSERT(descriptor); ++ ++ mali_mem_release(descriptor); ++ mali_mem_descriptor_destroy(descriptor); ++} ++ ++void mali_memory_session_end(struct mali_session_data *session) ++{ ++ MALI_DEBUG_PRINT(3, ("MMU session end\n")); ++ ++ if (NULL == session) { ++ MALI_DEBUG_PRINT(1, ("No session data found during session end\n")); ++ return; ++ } ++ ++ /* Lock the session so we can modify the memory list */ ++ _mali_osk_mutex_wait(session->memory_lock); ++ ++ /* Free all allocations still in the descriptor map, and terminate the map */ ++ if (NULL != session->descriptor_mapping) { ++ mali_descriptor_mapping_call_for_each(session->descriptor_mapping, descriptor_table_cleanup_callback); ++ mali_descriptor_mapping_destroy(session->descriptor_mapping); ++ session->descriptor_mapping = NULL; ++ } ++ ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ /* Free the lock */ ++ _mali_osk_mutex_term(session->memory_lock); ++ ++ return; ++} ++ ++_mali_osk_errcode_t mali_memory_initialize(void) ++{ ++ return mali_mem_os_init(); ++} ++ ++void mali_memory_terminate(void) ++{ ++ mali_mem_os_term(); ++ mali_mem_block_allocator_destroy(NULL); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.h +new file mode 100644 +index 0000000..a5a0216 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory.h +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MEMORY_H__ ++#define __MALI_MEMORY_H__ ++ ++#include "mali_osk.h" ++#include "mali_session.h" ++ ++#include ++#include ++ ++#include "mali_memory_types.h" ++#include "mali_memory_os_alloc.h" ++ ++_mali_osk_errcode_t mali_memory_initialize(void); ++void mali_memory_terminate(void); ++ ++/** @brief Allocate a page table page ++ * ++ * Allocate a page for use as a page directory or page table. The page is ++ * mapped into kernel space. ++ * ++ * @return _MALI_OSK_ERR_OK on success, otherwise an error code ++ * @param table_page GPU pointer to the allocated page ++ * @param mapping CPU pointer to the mapping of the allocated page ++ */ ++MALI_STATIC_INLINE _mali_osk_errcode_t mali_mmu_get_table_page(u32 *table_page, mali_io_address *mapping) ++{ ++ return mali_mem_os_get_table_page(table_page, mapping); ++} ++ ++/** @brief Release a page table page ++ * ++ * Release a page table page allocated through \a mali_mmu_get_table_page ++ * ++ * @param pa the GPU address of the page to release ++ */ ++MALI_STATIC_INLINE void mali_mmu_release_table_page(u32 phys, void *virt) ++{ ++ mali_mem_os_release_table_page(phys, virt); ++} ++ ++/** @brief mmap function ++ * ++ * mmap syscalls on the Mali device node will end up here. ++ * ++ * This function allocates Mali memory and maps it on CPU and Mali. ++ */ ++int mali_mmap(struct file *filp, struct vm_area_struct *vma); ++ ++/** @brief Allocate and initialize a Mali memory descriptor ++ * ++ * @param session Pointer to the session allocating the descriptor ++ * @param type Type of memory the descriptor will represent ++ */ ++mali_mem_allocation *mali_mem_descriptor_create(struct mali_session_data *session, mali_mem_type type); ++ ++/** @brief Destroy a Mali memory descriptor ++ * ++ * This function will only free the descriptor itself, and not the memory it ++ * represents. ++ * ++ * @param descriptor Pointer to the descriptor to destroy ++ */ ++void mali_mem_descriptor_destroy(mali_mem_allocation *descriptor); ++ ++/** @brief Start a new memory session ++ * ++ * Called when a process opens the Mali device node. ++ * ++ * @param session Pointer to session to initialize ++ */ ++_mali_osk_errcode_t mali_memory_session_begin(struct mali_session_data *session); ++ ++/** @brief Close a memory session ++ * ++ * Called when a process closes the Mali device node. ++ * ++ * Memory allocated by the session will be freed ++ * ++ * @param session Pointer to the session to terminate ++ */ ++void mali_memory_session_end(struct mali_session_data *session); ++ ++/** @brief Prepare Mali page tables for mapping ++ * ++ * This function will prepare the Mali page tables for mapping the memory ++ * described by \a descriptor. ++ * ++ * Page tables will be reference counted and allocated, if not yet present. ++ * ++ * @param descriptor Pointer to the memory descriptor to the mapping ++ */ ++_mali_osk_errcode_t mali_mem_mali_map_prepare(mali_mem_allocation *descriptor); ++ ++/** @brief Free Mali page tables for mapping ++ * ++ * This function will unmap pages from Mali memory and free the page tables ++ * that are now unused. ++ * ++ * The updated pages in the Mali L2 cache will be invalidated, and the MMU TLBs will be zapped if necessary. ++ * ++ * @param descriptor Pointer to the memory descriptor to unmap ++ */ ++void mali_mem_mali_map_free(mali_mem_allocation *descriptor); ++ ++/** @brief Parse resource and prepare the OS memory allocator ++ * ++ * @param size Maximum size to allocate for Mali GPU. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t mali_memory_core_resource_os_memory(u32 size); ++ ++/** @brief Parse resource and prepare the dedicated memory allocator ++ * ++ * @param start Physical start address of dedicated Mali GPU memory. ++ * @param size Size of dedicated Mali GPU memory. ++ * @return _MALI_OSK_ERR_OK on success, otherwise failure. ++ */ ++_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(u32 start, u32 size); ++ ++ ++void mali_mem_ump_release(mali_mem_allocation *descriptor); ++void mali_mem_external_release(mali_mem_allocation *descriptor); ++ ++#endif /* __MALI_MEMORY_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.c +new file mode 100644 +index 0000000..2847893 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.c +@@ -0,0 +1,319 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include "mali_kernel_common.h" ++#include "mali_memory.h" ++#include "mali_memory_block_alloc.h" ++#include "mali_osk.h" ++#include ++#define MALI_BLOCK_SIZE (256UL * 1024UL) /* 256 kB, remember to keep the ()s */ ++ ++struct block_info { ++ struct block_info *next; ++}; ++ ++typedef struct block_info block_info; ++ ++ ++typedef struct block_allocator { ++ struct mutex mutex; ++ block_info *all_blocks; ++ block_info *first_free; ++ u32 base; ++ u32 cpu_usage_adjust; ++ u32 num_blocks; ++ u32 free_blocks; ++} block_allocator; ++ ++static block_allocator *mali_mem_block_gobal_allocator = NULL; ++ ++MALI_STATIC_INLINE u32 get_phys(block_allocator *info, block_info *block) ++{ ++ return info->base + ((block - info->all_blocks) * MALI_BLOCK_SIZE); ++} ++ ++mali_mem_allocator *mali_mem_block_allocator_create(u32 base_address, u32 cpu_usage_adjust, u32 size) ++{ ++ block_allocator *info; ++ u32 usable_size; ++ u32 num_blocks; ++ ++ usable_size = size & ~(MALI_BLOCK_SIZE - 1); ++ MALI_DEBUG_PRINT(3, ("Mali block allocator create for region starting at 0x%08X length 0x%08X\n", base_address, size)); ++ MALI_DEBUG_PRINT(4, ("%d usable bytes\n", usable_size)); ++ num_blocks = usable_size / MALI_BLOCK_SIZE; ++ MALI_DEBUG_PRINT(4, ("which becomes %d blocks\n", num_blocks)); ++ ++ if (usable_size == 0) { ++ MALI_DEBUG_PRINT(1, ("Memory block of size %d is unusable\n", size)); ++ return NULL; ++ } ++ ++ info = _mali_osk_malloc(sizeof(block_allocator)); ++ if (NULL != info) { ++ mutex_init(&info->mutex); ++ info->all_blocks = _mali_osk_malloc(sizeof(block_info) * num_blocks); ++ if (NULL != info->all_blocks) { ++ u32 i; ++ info->first_free = NULL; ++ info->num_blocks = num_blocks; ++ info->free_blocks = num_blocks; ++ ++ info->base = base_address; ++ info->cpu_usage_adjust = cpu_usage_adjust; ++ ++ for ( i = 0; i < num_blocks; i++) { ++ info->all_blocks[i].next = info->first_free; ++ info->first_free = &info->all_blocks[i]; ++ } ++ ++ return (mali_mem_allocator *)info; ++ } ++ _mali_osk_free(info); ++ } ++ ++ return NULL; ++} ++ ++void mali_mem_block_allocator_destroy(mali_mem_allocator *allocator) ++{ ++ block_allocator *info = (block_allocator*)allocator; ++ ++ info = mali_mem_block_gobal_allocator; ++ if (NULL == info) return; ++ ++ MALI_DEBUG_ASSERT_POINTER(info); ++ ++ _mali_osk_free(info->all_blocks); ++ _mali_osk_free(info); ++} ++ ++static void mali_mem_block_mali_map(mali_mem_allocation *descriptor, u32 phys, u32 virt, u32 size) ++{ ++ struct mali_page_directory *pagedir = descriptor->session->page_directory; ++ u32 prop = descriptor->mali_mapping.properties; ++ u32 offset = 0; ++ ++ while (size) { ++ mali_mmu_pagedir_update(pagedir, virt + offset, phys + offset, MALI_MMU_PAGE_SIZE, prop); ++ ++ size -= MALI_MMU_PAGE_SIZE; ++ offset += MALI_MMU_PAGE_SIZE; ++ } ++} ++ ++static int mali_mem_block_cpu_map(mali_mem_allocation *descriptor, struct vm_area_struct *vma, u32 mali_phys, u32 mapping_offset, u32 size, u32 cpu_usage_adjust) ++{ ++ u32 virt = vma->vm_start + mapping_offset; ++ u32 cpu_phys = mali_phys + cpu_usage_adjust; ++ u32 offset = 0; ++ int ret; ++ ++ while (size) { ++ ret = vm_insert_pfn(vma, virt + offset, __phys_to_pfn(cpu_phys + offset)); ++ ++ if (unlikely(ret)) { ++ MALI_DEBUG_PRINT(1, ("Block allocator: Failed to insert pfn into vma\n")); ++ return 1; ++ } ++ ++ size -= MALI_MMU_PAGE_SIZE; ++ offset += MALI_MMU_PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++mali_mem_allocation *mali_mem_block_alloc(u32 mali_addr, u32 size, struct vm_area_struct *vma, struct mali_session_data *session) ++{ ++ _mali_osk_errcode_t err; ++ mali_mem_allocation *descriptor; ++ block_allocator *info; ++ u32 left; ++ block_info *last_allocated = NULL; ++ block_allocator_allocation *ret_allocation; ++ u32 offset = 0; ++ ++ size = ALIGN(size, MALI_BLOCK_SIZE); ++ ++ info = mali_mem_block_gobal_allocator; ++ if (NULL == info) return NULL; ++ ++ left = size; ++ MALI_DEBUG_ASSERT(0 != left); ++ ++ descriptor = mali_mem_descriptor_create(session, MALI_MEM_BLOCK); ++ if (NULL == descriptor) { ++ return NULL; ++ } ++ ++ descriptor->mali_mapping.addr = mali_addr; ++ descriptor->size = size; ++ descriptor->cpu_mapping.addr = (void __user*)vma->vm_start; ++ descriptor->cpu_mapping.ref = 1; ++ ++ if (VM_SHARED == (VM_SHARED & vma->vm_flags)) { ++ descriptor->mali_mapping.properties = MALI_MMU_FLAGS_DEFAULT; ++ } else { ++ /* Cached Mali memory mapping */ ++ descriptor->mali_mapping.properties = MALI_MMU_FLAGS_FORCE_GP_READ_ALLOCATE; ++ vma->vm_flags |= VM_SHARED; ++ } ++ ++ ret_allocation = &descriptor->block_mem.mem; ++ ++ ret_allocation->mapping_length = 0; ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ mutex_lock(&info->mutex); ++ ++ if (left > (info->free_blocks * MALI_BLOCK_SIZE)) { ++ MALI_DEBUG_PRINT(2, ("Mali block allocator: not enough free blocks to service allocation (%u)\n", left)); ++ mutex_unlock(&info->mutex); ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_descriptor_destroy(descriptor); ++ return NULL; ++ } ++ ++ err = mali_mem_mali_map_prepare(descriptor); ++ if (_MALI_OSK_ERR_OK != err) { ++ mutex_unlock(&info->mutex); ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_descriptor_destroy(descriptor); ++ return NULL; ++ } ++ ++ while ((left > 0) && (info->first_free)) { ++ block_info *block; ++ u32 phys_addr; ++ u32 current_mapping_size; ++ ++ block = info->first_free; ++ info->first_free = info->first_free->next; ++ block->next = last_allocated; ++ last_allocated = block; ++ ++ phys_addr = get_phys(info, block); ++ ++ if (MALI_BLOCK_SIZE < left) { ++ current_mapping_size = MALI_BLOCK_SIZE; ++ } else { ++ current_mapping_size = left; ++ } ++ ++ mali_mem_block_mali_map(descriptor, phys_addr, mali_addr + offset, current_mapping_size); ++ if (mali_mem_block_cpu_map(descriptor, vma, phys_addr, offset, current_mapping_size, info->cpu_usage_adjust)) { ++ /* release all memory back to the pool */ ++ while (last_allocated) { ++ /* This relinks every block we've just allocated back into the free-list */ ++ block = last_allocated->next; ++ last_allocated->next = info->first_free; ++ info->first_free = last_allocated; ++ last_allocated = block; ++ } ++ ++ mutex_unlock(&info->mutex); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ mali_mem_mali_map_free(descriptor); ++ mali_mem_descriptor_destroy(descriptor); ++ ++ return NULL; ++ } ++ ++ left -= current_mapping_size; ++ offset += current_mapping_size; ++ ret_allocation->mapping_length += current_mapping_size; ++ ++ --info->free_blocks; ++ } ++ ++ mutex_unlock(&info->mutex); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ MALI_DEBUG_ASSERT(0 == left); ++ ++ /* Record all the information about this allocation */ ++ ret_allocation->last_allocated = last_allocated; ++ ret_allocation->info = info; ++ ++ return descriptor; ++} ++ ++void mali_mem_block_release(mali_mem_allocation *descriptor) ++{ ++ block_allocator *info = descriptor->block_mem.mem.info; ++ block_info *block, *next; ++ block_allocator_allocation *allocation = &descriptor->block_mem.mem; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_BLOCK == descriptor->type); ++ ++ block = allocation->last_allocated; ++ ++ MALI_DEBUG_ASSERT_POINTER(block); ++ ++ /* unmap */ ++ mali_mem_mali_map_free(descriptor); ++ ++ mutex_lock(&info->mutex); ++ ++ while (block) { ++ MALI_DEBUG_ASSERT(!((block < info->all_blocks) || (block > (info->all_blocks + info->num_blocks)))); ++ ++ next = block->next; ++ ++ /* relink into free-list */ ++ block->next = info->first_free; ++ info->first_free = block; ++ ++ /* advance the loop */ ++ block = next; ++ ++ ++info->free_blocks; ++ } ++ ++ mutex_unlock(&info->mutex); ++} ++ ++u32 mali_mem_block_allocator_stat(void) ++{ ++ block_allocator *info = (block_allocator *)mali_mem_block_gobal_allocator; ++ ++ if (NULL == info) return 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(info); ++ ++ return (info->num_blocks - info->free_blocks) * MALI_BLOCK_SIZE; ++} ++ ++_mali_osk_errcode_t mali_memory_core_resource_dedicated_memory(u32 start, u32 size) ++{ ++ mali_mem_allocator *allocator; ++ ++ /* Do the low level linux operation first */ ++ ++ /* Request ownership of the memory */ ++ if (_MALI_OSK_ERR_OK != _mali_osk_mem_reqregion(start, size, "Dedicated Mali GPU memory")) { ++ MALI_DEBUG_PRINT(1, ("Failed to request memory region for frame buffer (0x%08X - 0x%08X)\n", start, start + size - 1)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ /* Create generic block allocator object to handle it */ ++ allocator = mali_mem_block_allocator_create(start, 0 /* cpu_usage_adjust */, size); ++ ++ if (NULL == allocator) { ++ MALI_DEBUG_PRINT(1, ("Memory bank registration failed\n")); ++ _mali_osk_mem_unreqregion(start, size); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ mali_mem_block_gobal_allocator = (block_allocator*)allocator; ++ ++ return _MALI_OSK_ERR_OK; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.h +new file mode 100644 +index 0000000..89bd541 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_block_alloc.h +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_BLOCK_ALLOCATOR_H__ ++#define __MALI_BLOCK_ALLOCATOR_H__ ++ ++#include "mali_session.h" ++#include "mali_memory.h" ++ ++#include "mali_memory_types.h" ++ ++typedef struct mali_mem_allocator mali_mem_allocator; ++ ++mali_mem_allocator *mali_block_allocator_create(u32 base_address, u32 cpu_usage_adjust, u32 size); ++void mali_mem_block_allocator_destroy(mali_mem_allocator *allocator); ++ ++mali_mem_allocation *mali_mem_block_alloc(u32 mali_addr, u32 size, struct vm_area_struct *vma, struct mali_session_data *session); ++void mali_mem_block_release(mali_mem_allocation *descriptor); ++ ++u32 mali_mem_block_allocator_stat(void); ++ ++#endif /* __MALI_BLOCK_ALLOCATOR_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.c +new file mode 100644 +index 0000000..60cae15 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.c +@@ -0,0 +1,434 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include /* file system operations */ ++#include /* user space access */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_kernel_linux.h" ++ ++#include "mali_memory.h" ++#include "mali_memory_dma_buf.h" ++ ++#include "mali_pp_job.h" ++ ++static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem); ++ ++struct mali_dma_buf_attachment { ++ struct dma_buf *buf; ++ struct dma_buf_attachment *attachment; ++ struct sg_table *sgt; ++ struct mali_session_data *session; ++ int map_ref; ++ struct mutex map_lock; ++ mali_bool is_mapped; ++ wait_queue_head_t wait_queue; ++}; ++ ++static void mali_dma_buf_release(struct mali_dma_buf_attachment *mem) ++{ ++ MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release attachment %p\n", mem)); ++ ++ MALI_DEBUG_ASSERT_POINTER(mem); ++ MALI_DEBUG_ASSERT_POINTER(mem->attachment); ++ MALI_DEBUG_ASSERT_POINTER(mem->buf); ++ ++#if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++ /* We mapped implicitly on attach, so we need to unmap on release */ ++ mali_dma_buf_unmap(mem); ++#endif ++ ++ /* Wait for buffer to become unmapped */ ++ wait_event(mem->wait_queue, !mem->is_mapped); ++ MALI_DEBUG_ASSERT(!mem->is_mapped); ++ ++ dma_buf_detach(mem->buf, mem->attachment); ++ dma_buf_put(mem->buf); ++ ++ _mali_osk_free(mem); ++} ++ ++void mali_mem_dma_buf_release(mali_mem_allocation *descriptor) ++{ ++ struct mali_dma_buf_attachment *mem = descriptor->dma_buf.attachment; ++ ++ mali_dma_buf_release(mem); ++} ++ ++/* ++ * Map DMA buf attachment \a mem into \a session at virtual address \a virt. ++ */ ++static int mali_dma_buf_map(struct mali_dma_buf_attachment *mem, struct mali_session_data *session, u32 virt, u32 flags) ++{ ++ struct mali_page_directory *pagedir; ++ struct scatterlist *sg; ++ int i; ++ ++ MALI_DEBUG_ASSERT_POINTER(mem); ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT(mem->session == session); ++ ++ mutex_lock(&mem->map_lock); ++ ++ mem->map_ref++; ++ ++ MALI_DEBUG_PRINT(5, ("Mali DMA-buf: map attachment %p, new map_ref = %d\n", mem, mem->map_ref)); ++ ++ if (1 == mem->map_ref) { ++ /* First reference taken, so we need to map the dma buf */ ++ MALI_DEBUG_ASSERT(!mem->is_mapped); ++ ++ pagedir = mali_session_get_page_directory(session); ++ MALI_DEBUG_ASSERT_POINTER(pagedir); ++ ++ mem->sgt = dma_buf_map_attachment(mem->attachment, DMA_BIDIRECTIONAL); ++ if (IS_ERR_OR_NULL(mem->sgt)) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf attachment\n")); ++ return -EFAULT; ++ } ++ ++ for_each_sg(mem->sgt->sgl, sg, mem->sgt->nents, i) { ++ u32 size = sg_dma_len(sg); ++ dma_addr_t phys = sg_dma_address(sg); ++ ++ /* sg must be page aligned. */ ++ MALI_DEBUG_ASSERT(0 == size % MALI_MMU_PAGE_SIZE); ++ ++ mali_mmu_pagedir_update(pagedir, virt, phys, size, MALI_MMU_FLAGS_DEFAULT); ++ ++ virt += size; ++ } ++ ++ if (flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) { ++ u32 guard_phys; ++ MALI_DEBUG_PRINT(7, ("Mapping in extra guard page\n")); ++ ++ guard_phys = sg_dma_address(mem->sgt->sgl); ++ mali_mmu_pagedir_update(pagedir, virt, guard_phys, MALI_MMU_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT); ++ } ++ ++ mem->is_mapped = MALI_TRUE; ++ mutex_unlock(&mem->map_lock); ++ ++ /* Wake up any thread waiting for buffer to become mapped */ ++ wake_up_all(&mem->wait_queue); ++ } else { ++ MALI_DEBUG_ASSERT(mem->is_mapped); ++ mutex_unlock(&mem->map_lock); ++ } ++ ++ return 0; ++} ++ ++static void mali_dma_buf_unmap(struct mali_dma_buf_attachment *mem) ++{ ++ MALI_DEBUG_ASSERT_POINTER(mem); ++ MALI_DEBUG_ASSERT_POINTER(mem->attachment); ++ MALI_DEBUG_ASSERT_POINTER(mem->buf); ++ ++ mutex_lock(&mem->map_lock); ++ ++ mem->map_ref--; ++ ++ MALI_DEBUG_PRINT(5, ("Mali DMA-buf: unmap attachment %p, new map_ref = %d\n", mem, mem->map_ref)); ++ ++ if (0 == mem->map_ref) { ++ dma_buf_unmap_attachment(mem->attachment, mem->sgt, DMA_BIDIRECTIONAL); ++ ++ mem->is_mapped = MALI_FALSE; ++ } ++ ++ mutex_unlock(&mem->map_lock); ++ ++ /* Wake up any thread waiting for buffer to become unmapped */ ++ wake_up_all(&mem->wait_queue); ++} ++ ++#if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++int mali_dma_buf_map_job(struct mali_pp_job *job) ++{ ++ mali_mem_allocation *descriptor; ++ struct mali_dma_buf_attachment *mem; ++ _mali_osk_errcode_t err; ++ int i; ++ int ret = 0; ++ ++ _mali_osk_mutex_wait(job->session->memory_lock); ++ ++ for (i = 0; i < job->num_memory_cookies; i++) { ++ int cookie = job->memory_cookies[i]; ++ ++ if (0 == cookie) { ++ /* 0 is not a valid cookie */ ++ MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]); ++ continue; ++ } ++ ++ MALI_DEBUG_ASSERT(0 < cookie); ++ ++ err = mali_descriptor_mapping_get(job->session->descriptor_mapping, ++ cookie, (void**)&descriptor); ++ ++ if (_MALI_OSK_ERR_OK != err) { ++ MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to get descriptor for cookie %d\n", cookie)); ++ ret = -EFAULT; ++ MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]); ++ continue; ++ } ++ ++ if (MALI_MEM_DMA_BUF != descriptor->type) { ++ /* Not a DMA-buf */ ++ MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]); ++ continue; ++ } ++ ++ mem = descriptor->dma_buf.attachment; ++ ++ MALI_DEBUG_ASSERT_POINTER(mem); ++ MALI_DEBUG_ASSERT(mem->session == job->session); ++ ++ err = mali_dma_buf_map(mem, mem->session, descriptor->mali_mapping.addr, descriptor->flags); ++ if (0 != err) { ++ MALI_DEBUG_PRINT_ERROR(("Mali DMA-buf: Failed to map dma-buf for cookie %d at mali address %x\b", ++ cookie, descriptor->mali_mapping.addr)); ++ ret = -EFAULT; ++ MALI_DEBUG_ASSERT(NULL == job->dma_bufs[i]); ++ continue; ++ } ++ ++ /* Add mem to list of DMA-bufs mapped for this job */ ++ job->dma_bufs[i] = mem; ++ } ++ ++ _mali_osk_mutex_signal(job->session->memory_lock); ++ ++ return ret; ++} ++ ++void mali_dma_buf_unmap_job(struct mali_pp_job *job) ++{ ++ int i; ++ for (i = 0; i < job->num_dma_bufs; i++) { ++ if (NULL == job->dma_bufs[i]) continue; ++ ++ mali_dma_buf_unmap(job->dma_bufs[i]); ++ job->dma_bufs[i] = NULL; ++ } ++} ++#endif /* !CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH */ ++ ++int mali_attach_dma_buf(struct mali_session_data *session, _mali_uk_attach_dma_buf_s __user *user_arg) ++{ ++ struct dma_buf *buf; ++ struct mali_dma_buf_attachment *mem; ++ _mali_uk_attach_dma_buf_s args; ++ mali_mem_allocation *descriptor; ++ int md; ++ int fd; ++ ++ /* Get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if (0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_attach_dma_buf_s))) { ++ return -EFAULT; ++ } ++ ++ if (args.mali_address & ~PAGE_MASK) { ++ MALI_DEBUG_PRINT_ERROR(("Requested address (0x%08x) is not page aligned\n", args.mali_address)); ++ return -EINVAL; ++ } ++ ++ if (args.mali_address >= args.mali_address + args.size) { ++ MALI_DEBUG_PRINT_ERROR(("Requested address and size (0x%08x + 0x%08x) is too big\n", args.mali_address, args.size)); ++ return -EINVAL; ++ } ++ ++ fd = args.mem_fd; ++ ++ buf = dma_buf_get(fd); ++ if (IS_ERR_OR_NULL(buf)) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to get dma-buf from fd: %d\n", fd)); ++ return PTR_RET(buf); ++ } ++ ++ /* Currently, mapping of the full buffer are supported. */ ++ if (args.size != buf->size) { ++ MALI_DEBUG_PRINT_ERROR(("dma-buf size doesn't match mapping size.\n")); ++ dma_buf_put(buf); ++ return -EINVAL; ++ } ++ ++ mem = _mali_osk_calloc(1, sizeof(struct mali_dma_buf_attachment)); ++ if (NULL == mem) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to allocate dma-buf tracing struct\n")); ++ dma_buf_put(buf); ++ return -ENOMEM; ++ } ++ ++ mem->buf = buf; ++ mem->session = session; ++ mem->map_ref = 0; ++ mutex_init(&mem->map_lock); ++ init_waitqueue_head(&mem->wait_queue); ++ ++ mem->attachment = dma_buf_attach(mem->buf, &mali_platform_device->dev); ++ if (NULL == mem->attachment) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to attach to dma-buf %d\n", fd)); ++ dma_buf_put(mem->buf); ++ _mali_osk_free(mem); ++ return -EFAULT; ++ } ++ ++ /* Set up Mali memory descriptor */ ++ descriptor = mali_mem_descriptor_create(session, MALI_MEM_DMA_BUF); ++ if (NULL == descriptor) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to allocate descriptor dma-buf %d\n", fd)); ++ mali_dma_buf_release(mem); ++ return -ENOMEM; ++ } ++ ++ descriptor->size = args.size; ++ descriptor->mali_mapping.addr = args.mali_address; ++ ++ descriptor->dma_buf.attachment = mem; ++ ++ descriptor->flags |= MALI_MEM_FLAG_DONT_CPU_MAP; ++ if (args.flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) { ++ descriptor->flags = MALI_MEM_FLAG_MALI_GUARD_PAGE; ++ } ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ ++ /* Map dma-buf into this session's page tables */ ++ if (_MALI_OSK_ERR_OK != mali_mem_mali_map_prepare(descriptor)) { ++ _mali_osk_mutex_signal(session->memory_lock); ++ MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf on Mali\n")); ++ mali_mem_descriptor_destroy(descriptor); ++ mali_dma_buf_release(mem); ++ return -ENOMEM; ++ } ++ ++#if defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++ /* Map memory into session's Mali virtual address space. */ ++ ++ if (0 != mali_dma_buf_map(mem, session, descriptor->mali_mapping.addr, descriptor->flags)) { ++ mali_mem_mali_map_free(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ MALI_DEBUG_PRINT_ERROR(("Failed to map dma-buf %d into Mali address space\n", fd)); ++ mali_mem_descriptor_destroy(descriptor); ++ mali_dma_buf_release(mem); ++ return -ENOMEM; ++ } ++ ++#endif ++ ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ /* Get descriptor mapping for memory. */ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &md)) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_mali_map_free(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ MALI_DEBUG_PRINT_ERROR(("Failed to create descriptor mapping for dma-buf %d\n", fd)); ++ mali_mem_descriptor_destroy(descriptor); ++ mali_dma_buf_release(mem); ++ return -EFAULT; ++ } ++ ++ /* Return stuff to user space */ ++ if (0 != put_user(md, &user_arg->cookie)) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_mali_map_free(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ MALI_DEBUG_PRINT_ERROR(("Failed to return descriptor to user space for dma-buf %d\n", fd)); ++ mali_descriptor_mapping_free(session->descriptor_mapping, md); ++ mali_dma_buf_release(mem); ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int mali_release_dma_buf(struct mali_session_data *session, _mali_uk_release_dma_buf_s __user *user_arg) ++{ ++ int ret = 0; ++ _mali_uk_release_dma_buf_s args; ++ mali_mem_allocation *descriptor; ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_release_dma_buf_s)) ) { ++ return -EFAULT; ++ } ++ ++ MALI_DEBUG_PRINT(3, ("Mali DMA-buf: release descriptor cookie %d\n", args.cookie)); ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ ++ descriptor = mali_descriptor_mapping_free(session->descriptor_mapping, args.cookie); ++ ++ if (NULL != descriptor) { ++ MALI_DEBUG_PRINT(3, ("Mali DMA-buf: Releasing dma-buf at mali address %x\n", descriptor->mali_mapping.addr)); ++ ++ mali_mem_mali_map_free(descriptor); ++ ++ mali_dma_buf_release(descriptor->dma_buf.attachment); ++ ++ mali_mem_descriptor_destroy(descriptor); ++ } else { ++ MALI_DEBUG_PRINT_ERROR(("Invalid memory descriptor %d used to release dma-buf\n", args.cookie)); ++ ret = -EINVAL; ++ } ++ ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ /* Return the error that _mali_ukk_map_external_ump_mem produced */ ++ return ret; ++} ++ ++int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *user_arg) ++{ ++ _mali_uk_dma_buf_get_size_s args; ++ int fd; ++ struct dma_buf *buf; ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&args, (void __user *)user_arg, sizeof(_mali_uk_dma_buf_get_size_s)) ) { ++ return -EFAULT; ++ } ++ ++ /* Do DMA-BUF stuff */ ++ fd = args.mem_fd; ++ ++ buf = dma_buf_get(fd); ++ if (IS_ERR_OR_NULL(buf)) { ++ MALI_DEBUG_PRINT_ERROR(("Failed to get dma-buf from fd: %d\n", fd)); ++ return PTR_RET(buf); ++ } ++ ++ if (0 != put_user(buf->size, &user_arg->size)) { ++ dma_buf_put(buf); ++ return -EFAULT; ++ } ++ ++ dma_buf_put(buf); ++ ++ return 0; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.h +new file mode 100644 +index 0000000..7ee4dc5 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_dma_buf.h +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MEMORY_DMA_BUF_H__ ++#define __MALI_MEMORY_DMA_BUF_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "mali_osk.h" ++#include "mali_memory.h" ++ ++struct mali_pp_job; ++ ++struct mali_dma_buf_attachment; ++ ++int mali_attach_dma_buf(struct mali_session_data *session, _mali_uk_attach_dma_buf_s __user *arg); ++int mali_release_dma_buf(struct mali_session_data *session, _mali_uk_release_dma_buf_s __user *arg); ++int mali_dma_buf_get_size(struct mali_session_data *session, _mali_uk_dma_buf_get_size_s __user *arg); ++ ++void mali_mem_dma_buf_release(mali_mem_allocation *descriptor); ++ ++#if !defined(CONFIG_MALI_DMA_BUF_MAP_ON_ATTACH) ++int mali_dma_buf_map_job(struct mali_pp_job *job); ++void mali_dma_buf_unmap_job(struct mali_pp_job *job); ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_MEMORY_DMA_BUF_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_external.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_external.c +new file mode 100644 +index 0000000..6d8e792 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_external.c +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_osk.h" ++#include "mali_memory.h" ++#include "mali_kernel_descriptor_mapping.h" ++#include "mali_mem_validation.h" ++#include "mali_uk_types.h" ++ ++void mali_mem_external_release(mali_mem_allocation *descriptor) ++{ ++ MALI_DEBUG_ASSERT(MALI_MEM_EXTERNAL == descriptor->type); ++ ++ mali_mem_mali_map_free(descriptor); ++} ++ ++_mali_osk_errcode_t _mali_ukk_map_external_mem(_mali_uk_map_external_mem_s *args) ++{ ++ struct mali_session_data *session; ++ mali_mem_allocation * descriptor; ++ int md; ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session = (struct mali_session_data *)args->ctx; ++ MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ /* check arguments */ ++ /* NULL might be a valid Mali address */ ++ if (! args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); ++ ++ /* size must be a multiple of the system page size */ ++ if (args->size % _MALI_OSK_MALI_PAGE_SIZE) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); ++ ++ MALI_DEBUG_PRINT(3, ++ ("Requested to map physical memory 0x%x-0x%x into virtual memory 0x%x\n", ++ (void*)args->phys_addr, ++ (void*)(args->phys_addr + args->size -1), ++ (void*)args->mali_address) ++ ); ++ ++ /* Validate the mali physical range */ ++ if (_MALI_OSK_ERR_OK != mali_mem_validation_check(args->phys_addr, args->size)) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ descriptor = mali_mem_descriptor_create(session, MALI_MEM_EXTERNAL); ++ if (NULL == descriptor) MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ ++ descriptor->mali_mapping.addr = args->mali_address; ++ descriptor->size = args->size; ++ ++ if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) { ++ descriptor->flags = MALI_MEM_FLAG_MALI_GUARD_PAGE; ++ } ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ { ++ u32 virt = descriptor->mali_mapping.addr; ++ u32 phys = args->phys_addr; ++ u32 size = args->size; ++ ++ err = mali_mem_mali_map_prepare(descriptor); ++ if (_MALI_OSK_ERR_OK != err) { ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_descriptor_destroy(descriptor); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ mali_mmu_pagedir_update(session->page_directory, virt, phys, size, MALI_MMU_FLAGS_DEFAULT); ++ ++ if (descriptor->flags & MALI_MEM_FLAG_MALI_GUARD_PAGE) { ++ mali_mmu_pagedir_update(session->page_directory, virt + size, phys, _MALI_OSK_MALI_PAGE_SIZE, MALI_MMU_FLAGS_DEFAULT); ++ } ++ } ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &md)) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_external_release(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_descriptor_destroy(descriptor); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ args->cookie = md; ++ ++ MALI_SUCCESS; ++} ++ ++_mali_osk_errcode_t _mali_ukk_unmap_external_mem( _mali_uk_unmap_external_mem_s *args ) ++{ ++ mali_mem_allocation * descriptor; ++ void* old_value; ++ struct mali_session_data *session; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session = (struct mali_session_data *)args->ctx; ++ MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session->descriptor_mapping, args->cookie, (void**)&descriptor)) { ++ MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to unmap external memory\n", args->cookie)); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ old_value = mali_descriptor_mapping_free(session->descriptor_mapping, args->cookie); ++ ++ if (NULL != old_value) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_external_release(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_descriptor_destroy(descriptor); ++ } ++ ++ MALI_SUCCESS; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.c +new file mode 100644 +index 0000000..b94ffba +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.c +@@ -0,0 +1,556 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mali_osk.h" ++#include "mali_memory.h" ++#include "mali_memory_os_alloc.h" ++#include "mali_kernel_linux.h" ++ ++/* Minimum size of allocator page pool */ ++#define MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB * 256) ++#define MALI_OS_MEMORY_POOL_TRIM_JIFFIES (10 * CONFIG_HZ) /* Default to 10s */ ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) ++static int mali_mem_os_shrink(int nr_to_scan, gfp_t gfp_mask); ++#else ++static int mali_mem_os_shrink(struct shrinker *shrinker, int nr_to_scan, gfp_t gfp_mask); ++#endif ++#else ++static int mali_mem_os_shrink(struct shrinker *shrinker, struct shrink_control *sc); ++#endif ++static void mali_mem_os_trim_pool(struct work_struct *work); ++ ++static struct mali_mem_os_allocator { ++ spinlock_t pool_lock; ++ struct list_head pool_pages; ++ size_t pool_count; ++ ++ atomic_t allocated_pages; ++ size_t allocation_limit; ++ ++ struct shrinker shrinker; ++ struct delayed_work timed_shrinker; ++ struct workqueue_struct *wq; ++} mali_mem_os_allocator = { ++ .pool_lock = __SPIN_LOCK_UNLOCKED(pool_lock), ++ .pool_pages = LIST_HEAD_INIT(mali_mem_os_allocator.pool_pages), ++ .pool_count = 0, ++ ++ .allocated_pages = ATOMIC_INIT(0), ++ .allocation_limit = 0, ++ ++ .shrinker.shrink = mali_mem_os_shrink, ++ .shrinker.seeks = DEFAULT_SEEKS, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) ++ .timed_shrinker = __DELAYED_WORK_INITIALIZER(mali_mem_os_allocator.timed_shrinker, mali_mem_os_trim_pool, TIMER_DEFERRABLE), ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38) ++ .timed_shrinker = __DEFERRED_WORK_INITIALIZER(mali_mem_os_allocator.timed_shrinker, mali_mem_os_trim_pool), ++#else ++ .timed_shrinker = __DELAYED_WORK_INITIALIZER(mali_mem_os_allocator.timed_shrinker, mali_mem_os_trim_pool), ++#endif ++}; ++ ++static void mali_mem_os_free(mali_mem_allocation *descriptor) ++{ ++ LIST_HEAD(pages); ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_OS == descriptor->type); ++ ++ atomic_sub(descriptor->os_mem.count, &mali_mem_os_allocator.allocated_pages); ++ ++ /* Put pages on pool. */ ++ list_cut_position(&pages, &descriptor->os_mem.pages, descriptor->os_mem.pages.prev); ++ ++ spin_lock(&mali_mem_os_allocator.pool_lock); ++ ++ list_splice(&pages, &mali_mem_os_allocator.pool_pages); ++ mali_mem_os_allocator.pool_count += descriptor->os_mem.count; ++ ++ spin_unlock(&mali_mem_os_allocator.pool_lock); ++ ++ if (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES < mali_mem_os_allocator.pool_count) { ++ MALI_DEBUG_PRINT(5, ("OS Mem: Starting pool trim timer %u\n", mali_mem_os_allocator.pool_count)); ++ queue_delayed_work(mali_mem_os_allocator.wq, &mali_mem_os_allocator.timed_shrinker, MALI_OS_MEMORY_POOL_TRIM_JIFFIES); ++ } ++} ++ ++static int mali_mem_os_alloc_pages(mali_mem_allocation *descriptor, u32 size) ++{ ++ struct page *new_page, *tmp; ++ LIST_HEAD(pages); ++ size_t page_count = PAGE_ALIGN(size) / _MALI_OSK_MALI_PAGE_SIZE; ++ size_t remaining = page_count; ++ u32 i; ++ ++ MALI_DEBUG_ASSERT_POINTER(descriptor); ++ MALI_DEBUG_ASSERT(MALI_MEM_OS == descriptor->type); ++ ++ INIT_LIST_HEAD(&descriptor->os_mem.pages); ++ descriptor->os_mem.count = page_count; ++ ++ /* Grab pages from pool. */ ++ { ++ size_t pool_pages; ++ spin_lock(&mali_mem_os_allocator.pool_lock); ++ pool_pages = min(remaining, mali_mem_os_allocator.pool_count); ++ for (i = pool_pages; i > 0; i--) { ++ BUG_ON(list_empty(&mali_mem_os_allocator.pool_pages)); ++ list_move(mali_mem_os_allocator.pool_pages.next, &pages); ++ } ++ mali_mem_os_allocator.pool_count -= pool_pages; ++ remaining -= pool_pages; ++ spin_unlock(&mali_mem_os_allocator.pool_lock); ++ } ++ ++ /* Process pages from pool. */ ++ i = 0; ++ list_for_each_entry_safe(new_page, tmp, &pages, lru) { ++ BUG_ON(NULL == new_page); ++ ++ list_move_tail(&new_page->lru, &descriptor->os_mem.pages); ++ } ++ ++ /* Allocate new pages, if needed. */ ++ for (i = 0; i < remaining; i++) { ++ dma_addr_t dma_addr; ++ ++ new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN | __GFP_COLD); ++ ++ if (unlikely(NULL == new_page)) { ++ /* Calculate the number of pages actually allocated, and free them. */ ++ descriptor->os_mem.count = (page_count - remaining) + i; ++ atomic_add(descriptor->os_mem.count, &mali_mem_os_allocator.allocated_pages); ++ mali_mem_os_free(descriptor); ++ return -ENOMEM; ++ } ++ ++ /* Ensure page is flushed from CPU caches. */ ++ dma_addr = dma_map_page(&mali_platform_device->dev, new_page, ++ 0, _MALI_OSK_MALI_PAGE_SIZE, DMA_TO_DEVICE); ++ ++ /* Store page phys addr */ ++ SetPagePrivate(new_page); ++ set_page_private(new_page, dma_addr); ++ ++ list_add_tail(&new_page->lru, &descriptor->os_mem.pages); ++ } ++ ++ atomic_add(page_count, &mali_mem_os_allocator.allocated_pages); ++ ++ if (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES > mali_mem_os_allocator.pool_count) { ++ MALI_DEBUG_PRINT(4, ("OS Mem: Stopping pool trim timer, only %u pages on pool\n", mali_mem_os_allocator.pool_count)); ++ cancel_delayed_work(&mali_mem_os_allocator.timed_shrinker); ++ } ++ ++ return 0; ++} ++ ++static int mali_mem_os_mali_map(mali_mem_allocation *descriptor, struct mali_session_data *session) ++{ ++ struct mali_page_directory *pagedir = session->page_directory; ++ struct page *page; ++ _mali_osk_errcode_t err; ++ u32 virt = descriptor->mali_mapping.addr; ++ u32 prop = descriptor->mali_mapping.properties; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_OS == descriptor->type); ++ ++ err = mali_mem_mali_map_prepare(descriptor); ++ if (_MALI_OSK_ERR_OK != err) { ++ return -ENOMEM; ++ } ++ ++ list_for_each_entry(page, &descriptor->os_mem.pages, lru) { ++ u32 phys = page_private(page); ++ mali_mmu_pagedir_update(pagedir, virt, phys, MALI_MMU_PAGE_SIZE, prop); ++ virt += MALI_MMU_PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++static void mali_mem_os_mali_unmap(struct mali_session_data *session, mali_mem_allocation *descriptor) ++{ ++ mali_mem_mali_map_free(descriptor); ++} ++ ++static int mali_mem_os_cpu_map(mali_mem_allocation *descriptor, struct vm_area_struct *vma) ++{ ++ struct page *page; ++ int ret; ++ unsigned long addr = vma->vm_start; ++ ++ list_for_each_entry(page, &descriptor->os_mem.pages, lru) { ++ /* We should use vm_insert_page, but it does a dcache ++ * flush which makes it way slower than remap_pfn_range or vm_insert_pfn. ++ ret = vm_insert_page(vma, addr, page); ++ */ ++ ret = vm_insert_pfn(vma, addr, page_to_pfn(page)); ++ ++ if (unlikely(0 != ret)) { ++ return -EFAULT; ++ } ++ addr += _MALI_OSK_MALI_PAGE_SIZE; ++ } ++ ++ return 0; ++} ++ ++mali_mem_allocation *mali_mem_os_alloc(u32 mali_addr, u32 size, struct vm_area_struct *vma, struct mali_session_data *session) ++{ ++ mali_mem_allocation *descriptor; ++ int err; ++ ++ if (atomic_read(&mali_mem_os_allocator.allocated_pages) * _MALI_OSK_MALI_PAGE_SIZE + size > mali_mem_os_allocator.allocation_limit) { ++ MALI_DEBUG_PRINT(2, ("Mali Mem: Unable to allocate %u bytes. Currently allocated: %lu, max limit %lu\n", ++ size, ++ atomic_read(&mali_mem_os_allocator.allocated_pages) * _MALI_OSK_MALI_PAGE_SIZE, ++ mali_mem_os_allocator.allocation_limit)); ++ return NULL; ++ } ++ ++ descriptor = mali_mem_descriptor_create(session, MALI_MEM_OS); ++ if (NULL == descriptor) return NULL; ++ ++ descriptor->mali_mapping.addr = mali_addr; ++ descriptor->size = size; ++ descriptor->cpu_mapping.addr = (void __user*)vma->vm_start; ++ descriptor->cpu_mapping.ref = 1; ++ ++ if (VM_SHARED == (VM_SHARED & vma->vm_flags)) { ++ descriptor->mali_mapping.properties = MALI_MMU_FLAGS_DEFAULT; ++ } else { ++ /* Cached Mali memory mapping */ ++ descriptor->mali_mapping.properties = MALI_MMU_FLAGS_FORCE_GP_READ_ALLOCATE; ++ vma->vm_flags |= VM_SHARED; ++ } ++ ++ err = mali_mem_os_alloc_pages(descriptor, size); /* Allocate pages */ ++ if (0 != err) goto alloc_failed; ++ ++ /* Take session memory lock */ ++ _mali_osk_mutex_wait(session->memory_lock); ++ ++ err = mali_mem_os_mali_map(descriptor, session); /* Map on Mali */ ++ if (0 != err) goto mali_map_failed; ++ ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ err = mali_mem_os_cpu_map(descriptor, vma); /* Map on CPU */ ++ if (0 != err) goto cpu_map_failed; ++ ++ return descriptor; ++ ++cpu_map_failed: ++ mali_mem_os_mali_unmap(session, descriptor); ++mali_map_failed: ++ _mali_osk_mutex_signal(session->memory_lock); ++ mali_mem_os_free(descriptor); ++alloc_failed: ++ mali_mem_descriptor_destroy(descriptor); ++ MALI_DEBUG_PRINT(2, ("OS allocator: Failed to allocate memory (%d)\n", err)); ++ return NULL; ++} ++ ++void mali_mem_os_release(mali_mem_allocation *descriptor) ++{ ++ struct mali_session_data *session = descriptor->session; ++ ++ /* Unmap the memory from the mali virtual address space. */ ++ mali_mem_os_mali_unmap(session, descriptor); ++ ++ /* Free pages */ ++ mali_mem_os_free(descriptor); ++} ++ ++ ++#define MALI_MEM_OS_PAGE_TABLE_PAGE_POOL_SIZE 128 ++static struct { ++ struct { ++ u32 phys; ++ mali_io_address mapping; ++ } page[MALI_MEM_OS_PAGE_TABLE_PAGE_POOL_SIZE]; ++ u32 count; ++ spinlock_t lock; ++} mali_mem_page_table_page_pool = { ++ .count = 0, ++ .lock = __SPIN_LOCK_UNLOCKED(pool_lock), ++}; ++ ++_mali_osk_errcode_t mali_mem_os_get_table_page(u32 *phys, mali_io_address *mapping) ++{ ++ _mali_osk_errcode_t ret = _MALI_OSK_ERR_NOMEM; ++ ++ spin_lock(&mali_mem_page_table_page_pool.lock); ++ if (0 < mali_mem_page_table_page_pool.count) { ++ u32 i = --mali_mem_page_table_page_pool.count; ++ *phys = mali_mem_page_table_page_pool.page[i].phys; ++ *mapping = mali_mem_page_table_page_pool.page[i].mapping; ++ ++ ret = _MALI_OSK_ERR_OK; ++ } ++ spin_unlock(&mali_mem_page_table_page_pool.lock); ++ ++ if (_MALI_OSK_ERR_OK != ret) { ++ *mapping = dma_alloc_writecombine(&mali_platform_device->dev, _MALI_OSK_MALI_PAGE_SIZE, phys, GFP_ATOMIC); ++ if (NULL != *mapping) { ++ ret = _MALI_OSK_ERR_OK; ++ } ++ } ++ ++ return ret; ++} ++ ++void mali_mem_os_release_table_page(u32 phys, void *virt) ++{ ++ spin_lock(&mali_mem_page_table_page_pool.lock); ++ if (MALI_MEM_OS_PAGE_TABLE_PAGE_POOL_SIZE > mali_mem_page_table_page_pool.count) { ++ u32 i = mali_mem_page_table_page_pool.count; ++ mali_mem_page_table_page_pool.page[i].phys = phys; ++ mali_mem_page_table_page_pool.page[i].mapping = virt; ++ ++ ++mali_mem_page_table_page_pool.count; ++ ++ spin_unlock(&mali_mem_page_table_page_pool.lock); ++ } else { ++ spin_unlock(&mali_mem_page_table_page_pool.lock); ++ ++ dma_free_writecombine(&mali_platform_device->dev, _MALI_OSK_MALI_PAGE_SIZE, virt, phys); ++ } ++} ++ ++static void mali_mem_os_free_page(struct page *page) ++{ ++ BUG_ON(page_count(page) != 1); ++ ++ dma_unmap_page(&mali_platform_device->dev, page_private(page), ++ _MALI_OSK_MALI_PAGE_SIZE, DMA_TO_DEVICE); ++ ++ ClearPagePrivate(page); ++ ++ __free_page(page); ++} ++ ++/* The maximum number of page table pool pages to free in one go. */ ++#define MALI_MEM_OS_CHUNK_TO_FREE 64UL ++ ++/* Free a certain number of pages from the page table page pool. ++ * The pool lock must be held when calling the function, and the lock will be ++ * released before returning. ++ */ ++static void mali_mem_os_page_table_pool_free(size_t nr_to_free) ++{ ++ u32 phys_arr[MALI_MEM_OS_CHUNK_TO_FREE]; ++ void *virt_arr[MALI_MEM_OS_CHUNK_TO_FREE]; ++ u32 i; ++ ++ MALI_DEBUG_ASSERT(nr_to_free <= MALI_MEM_OS_CHUNK_TO_FREE); ++ ++ /* Remove nr_to_free pages from the pool and store them locally on stack. */ ++ for (i = 0; i < nr_to_free; i++) { ++ u32 pool_index = mali_mem_page_table_page_pool.count - i - 1; ++ ++ phys_arr[i] = mali_mem_page_table_page_pool.page[pool_index].phys; ++ virt_arr[i] = mali_mem_page_table_page_pool.page[pool_index].mapping; ++ } ++ ++ mali_mem_page_table_page_pool.count -= nr_to_free; ++ ++ spin_unlock(&mali_mem_page_table_page_pool.lock); ++ ++ /* After releasing the spinlock: free the pages we removed from the pool. */ ++ for (i = 0; i < nr_to_free; i++) { ++ dma_free_writecombine(&mali_platform_device->dev, _MALI_OSK_MALI_PAGE_SIZE, virt_arr[i], phys_arr[i]); ++ } ++} ++ ++static void mali_mem_os_trim_page_table_page_pool(void) ++{ ++ size_t nr_to_free = 0; ++ size_t nr_to_keep; ++ ++ /* Keep 2 page table pages for each 1024 pages in the page cache. */ ++ nr_to_keep = mali_mem_os_allocator.pool_count / 512; ++ /* And a minimum of eight pages, to accomodate new sessions. */ ++ nr_to_keep += 8; ++ ++ if (0 == spin_trylock(&mali_mem_page_table_page_pool.lock)) return; ++ ++ if (nr_to_keep < mali_mem_page_table_page_pool.count) { ++ nr_to_free = mali_mem_page_table_page_pool.count - nr_to_keep; ++ nr_to_free = min((size_t)MALI_MEM_OS_CHUNK_TO_FREE, nr_to_free); ++ } ++ ++ /* Pool lock will be released by the callee. */ ++ mali_mem_os_page_table_pool_free(nr_to_free); ++} ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) ++static int mali_mem_os_shrink(int nr_to_scan, gfp_t gfp_mask) ++#else ++static int mali_mem_os_shrink(struct shrinker *shrinker, int nr_to_scan, gfp_t gfp_mask) ++#endif ++#else ++static int mali_mem_os_shrink(struct shrinker *shrinker, struct shrink_control *sc) ++#endif ++{ ++ struct page *page, *tmp; ++ unsigned long flags; ++ struct list_head *le, pages; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) ++ int nr = nr_to_scan; ++#else ++ int nr = sc->nr_to_scan; ++#endif ++ ++ if (0 == nr) { ++ return mali_mem_os_allocator.pool_count + mali_mem_page_table_page_pool.count; ++ } ++ ++ if (0 == mali_mem_os_allocator.pool_count) { ++ /* No pages availble */ ++ return 0; ++ } ++ ++ if (0 == spin_trylock_irqsave(&mali_mem_os_allocator.pool_lock, flags)) { ++ /* Not able to lock. */ ++ return -1; ++ } ++ ++ /* Release from general page pool */ ++ nr = min((size_t)nr, mali_mem_os_allocator.pool_count); ++ mali_mem_os_allocator.pool_count -= nr; ++ list_for_each(le, &mali_mem_os_allocator.pool_pages) { ++ --nr; ++ if (0 == nr) break; ++ } ++ list_cut_position(&pages, &mali_mem_os_allocator.pool_pages, le); ++ spin_unlock_irqrestore(&mali_mem_os_allocator.pool_lock, flags); ++ ++ list_for_each_entry_safe(page, tmp, &pages, lru) { ++ mali_mem_os_free_page(page); ++ } ++ ++ /* Release some pages from page table page pool */ ++ mali_mem_os_trim_page_table_page_pool(); ++ ++ if (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES > mali_mem_os_allocator.pool_count) { ++ /* Pools are empty, stop timer */ ++ MALI_DEBUG_PRINT(5, ("Stopping timer, only %u pages on pool\n", mali_mem_os_allocator.pool_count)); ++ cancel_delayed_work(&mali_mem_os_allocator.timed_shrinker); ++ } ++ ++ return mali_mem_os_allocator.pool_count + mali_mem_page_table_page_pool.count; ++} ++ ++static void mali_mem_os_trim_pool(struct work_struct *data) ++{ ++ struct page *page, *tmp; ++ struct list_head *le; ++ LIST_HEAD(pages); ++ size_t nr_to_free; ++ ++ MALI_IGNORE(data); ++ ++ MALI_DEBUG_PRINT(3, ("OS Mem: Trimming pool %u\n", mali_mem_os_allocator.pool_count)); ++ ++ /* Release from general page pool */ ++ spin_lock(&mali_mem_os_allocator.pool_lock); ++ if (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES < mali_mem_os_allocator.pool_count) { ++ size_t count = mali_mem_os_allocator.pool_count - MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES; ++ /* Free half the pages on the pool above the static limit. Or 64 pages, 256KB. */ ++ nr_to_free = max(count / 2, (size_t)64); ++ ++ mali_mem_os_allocator.pool_count -= nr_to_free; ++ list_for_each(le, &mali_mem_os_allocator.pool_pages) { ++ --nr_to_free; ++ if (0 == nr_to_free) break; ++ } ++ list_cut_position(&pages, &mali_mem_os_allocator.pool_pages, le); ++ } ++ spin_unlock(&mali_mem_os_allocator.pool_lock); ++ ++ list_for_each_entry_safe(page, tmp, &pages, lru) { ++ mali_mem_os_free_page(page); ++ } ++ ++ /* Release some pages from page table page pool */ ++ mali_mem_os_trim_page_table_page_pool(); ++ ++ if (MALI_OS_MEMORY_KERNEL_BUFFER_SIZE_IN_PAGES < mali_mem_os_allocator.pool_count) { ++ MALI_DEBUG_PRINT(4, ("OS Mem: Starting pool trim timer %u\n", mali_mem_os_allocator.pool_count)); ++ queue_delayed_work(mali_mem_os_allocator.wq, &mali_mem_os_allocator.timed_shrinker, MALI_OS_MEMORY_POOL_TRIM_JIFFIES); ++ } ++} ++ ++_mali_osk_errcode_t mali_mem_os_init(void) ++{ ++ mali_mem_os_allocator.wq = alloc_workqueue("mali-mem", WQ_UNBOUND, 1); ++ if (NULL == mali_mem_os_allocator.wq) { ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ register_shrinker(&mali_mem_os_allocator.shrinker); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void mali_mem_os_term(void) ++{ ++ struct page *page, *tmp; ++ ++ unregister_shrinker(&mali_mem_os_allocator.shrinker); ++ cancel_delayed_work_sync(&mali_mem_os_allocator.timed_shrinker); ++ destroy_workqueue(mali_mem_os_allocator.wq); ++ ++ spin_lock(&mali_mem_os_allocator.pool_lock); ++ list_for_each_entry_safe(page, tmp, &mali_mem_os_allocator.pool_pages, lru) { ++ mali_mem_os_free_page(page); ++ ++ --mali_mem_os_allocator.pool_count; ++ } ++ BUG_ON(mali_mem_os_allocator.pool_count); ++ spin_unlock(&mali_mem_os_allocator.pool_lock); ++ ++ /* Release from page table page pool */ ++ do { ++ u32 nr_to_free; ++ ++ spin_lock(&mali_mem_page_table_page_pool.lock); ++ ++ nr_to_free = min((size_t)MALI_MEM_OS_CHUNK_TO_FREE, mali_mem_page_table_page_pool.count); ++ ++ /* Pool lock will be released by the callee. */ ++ mali_mem_os_page_table_pool_free(nr_to_free); ++ } while (0 != mali_mem_page_table_page_pool.count); ++} ++ ++_mali_osk_errcode_t mali_memory_core_resource_os_memory(u32 size) ++{ ++ mali_mem_os_allocator.allocation_limit = size; ++ ++ MALI_SUCCESS; ++} ++ ++u32 mali_mem_os_stat(void) ++{ ++ return atomic_read(&mali_mem_os_allocator.allocated_pages) * _MALI_OSK_MALI_PAGE_SIZE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.h +new file mode 100644 +index 0000000..12d3f4f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_os_alloc.h +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MEMORY_OS_ALLOC_H__ ++#define __MALI_MEMORY_OS_ALLOC_H__ ++ ++#include "mali_osk.h" ++#include "mali_session.h" ++ ++#include "mali_memory_types.h" ++ ++/* OS memory allocator */ ++/** @brief Allocate memory from OS ++ * ++ * This function will create a descriptor, allocate pages and map these on the CPU and Mali. ++ * ++ * @param mali_addr Mali virtual address to use for Mali mapping ++ * @param size Size to allocate ++ * @param vma Pointer to vma for CPU mapping ++ * @param session Pointer to session doing the allocation ++ */ ++mali_mem_allocation *mali_mem_os_alloc(u32 mali_addr, u32 size, struct vm_area_struct *vma, struct mali_session_data *session); ++ ++/** @brief Release Mali OS memory ++ * ++ * The session memory_lock must be held when calling this function. ++ * ++ * @param descriptor Pointer to the descriptor to release ++ */ ++void mali_mem_os_release(mali_mem_allocation *descriptor); ++ ++_mali_osk_errcode_t mali_mem_os_get_table_page(u32 *phys, mali_io_address *mapping); ++ ++void mali_mem_os_release_table_page(u32 phys, void *virt); ++ ++_mali_osk_errcode_t mali_mem_os_init(void); ++void mali_mem_os_term(void); ++u32 mali_mem_os_stat(void); ++ ++#endif /* __MALI_MEMORY_OS_ALLOC_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_types.h +new file mode 100644 +index 0000000..1067278 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_types.h +@@ -0,0 +1,100 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_MEMORY_TYPES_H__ ++#define __MALI_MEMORY_TYPES_H__ ++ ++#if defined(CONFIG_MALI400_UMP) ++#include "ump_kernel_interface.h" ++#endif ++ ++typedef u32 mali_address_t; ++ ++typedef enum mali_mem_type { ++ MALI_MEM_OS, ++ MALI_MEM_EXTERNAL, ++ MALI_MEM_DMA_BUF, ++ MALI_MEM_UMP, ++ MALI_MEM_BLOCK, ++} mali_mem_type; ++ ++typedef struct mali_mem_os_mem { ++ struct list_head pages; ++ u32 count; ++} mali_mem_os_mem; ++ ++typedef struct mali_mem_dma_buf { ++#if defined(CONFIG_DMA_SHARED_BUFFER) ++ struct mali_dma_buf_attachment *attachment; ++#endif ++} mali_mem_dma_buf; ++ ++typedef struct mali_mem_external { ++ dma_addr_t phys; ++ u32 size; ++} mali_mem_external; ++ ++typedef struct mali_mem_ump { ++#if defined(CONFIG_MALI400_UMP) ++ ump_dd_handle handle; ++#endif ++} mali_mem_ump; ++ ++typedef struct block_allocator_allocation { ++ /* The list will be released in reverse order */ ++ struct block_info *last_allocated; ++ u32 mapping_length; ++ struct block_allocator *info; ++} block_allocator_allocation; ++ ++typedef struct mali_mem_block_mem { ++ block_allocator_allocation mem; ++} mali_mem_block_mem; ++ ++typedef struct mali_mem_virt_mali_mapping { ++ mali_address_t addr; /* Virtual Mali address */ ++ u32 properties; /* MMU Permissions + cache, must match MMU HW */ ++} mali_mem_virt_mali_mapping; ++ ++typedef struct mali_mem_virt_cpu_mapping { ++ void __user *addr; ++ u32 ref; ++} mali_mem_virt_cpu_mapping; ++ ++#define MALI_MEM_ALLOCATION_VALID_MAGIC 0xdeda110c ++#define MALI_MEM_ALLOCATION_FREED_MAGIC 0x10101010 ++ ++typedef struct mali_mem_allocation { ++ MALI_DEBUG_CODE(u32 magic); ++ mali_mem_type type; /**< Type of memory */ ++ int id; /**< ID in the descriptor map for this allocation */ ++ ++ u32 size; /**< Size of the allocation */ ++ u32 flags; /**< Flags for this allocation */ ++ ++ struct mali_session_data *session; /**< Pointer to session that owns the allocation */ ++ ++ /* Union selected by type. */ ++ union { ++ mali_mem_os_mem os_mem; /**< MALI_MEM_OS */ ++ mali_mem_external ext_mem; /**< MALI_MEM_EXTERNAL */ ++ mali_mem_dma_buf dma_buf; /**< MALI_MEM_DMA_BUF */ ++ mali_mem_ump ump_mem; /**< MALI_MEM_UMP */ ++ mali_mem_block_mem block_mem; /**< MALI_MEM_BLOCK */ ++ }; ++ ++ mali_mem_virt_cpu_mapping cpu_mapping; /**< CPU mapping */ ++ mali_mem_virt_mali_mapping mali_mapping; /**< Mali mapping */ ++} mali_mem_allocation; ++ ++#define MALI_MEM_FLAG_MALI_GUARD_PAGE (1 << 0) ++#define MALI_MEM_FLAG_DONT_CPU_MAP (1 << 1) ++ ++#endif /* __MALI_MEMORY_TYPES__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_ump.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_ump.c +new file mode 100644 +index 0000000..1115c1d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_memory_ump.c +@@ -0,0 +1,215 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_kernel_linux.h" ++ ++#include "mali_memory.h" ++ ++#include "ump_kernel_interface.h" ++ ++static int mali_ump_map(struct mali_session_data *session, mali_mem_allocation *descriptor) ++{ ++ ump_dd_handle ump_mem; ++ u32 nr_blocks; ++ u32 i; ++ ump_dd_physical_block *ump_blocks; ++ struct mali_page_directory *pagedir; ++ u32 offset = 0; ++ u32 prop; ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ MALI_DEBUG_ASSERT_POINTER(descriptor); ++ MALI_DEBUG_ASSERT(MALI_MEM_UMP == descriptor->type); ++ ++ ump_mem = descriptor->ump_mem.handle; ++ MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID != ump_mem); ++ ++ nr_blocks = ump_dd_phys_block_count_get(ump_mem); ++ if (nr_blocks == 0) { ++ MALI_DEBUG_PRINT(1, ("No block count\n")); ++ return -EINVAL; ++ } ++ ++ ump_blocks = _mali_osk_malloc(sizeof(*ump_blocks)*nr_blocks); ++ if (NULL == ump_blocks) { ++ return -ENOMEM; ++ } ++ ++ if (UMP_DD_INVALID == ump_dd_phys_blocks_get(ump_mem, ump_blocks, nr_blocks)) { ++ _mali_osk_free(ump_blocks); ++ return -EFAULT; ++ } ++ ++ pagedir = session->page_directory; ++ prop = descriptor->mali_mapping.properties; ++ ++ err = mali_mem_mali_map_prepare(descriptor); ++ if (_MALI_OSK_ERR_OK != err) { ++ MALI_DEBUG_PRINT(1, ("Mapping of UMP memory failed\n")); ++ ++ _mali_osk_free(ump_blocks); ++ return -ENOMEM; ++ } ++ ++ for(i = 0; i < nr_blocks; ++i) { ++ u32 virt = descriptor->mali_mapping.addr + offset; ++ ++ MALI_DEBUG_PRINT(7, ("Mapping in 0x%08x size %d\n", ump_blocks[i].addr , ump_blocks[i].size)); ++ ++ mali_mmu_pagedir_update(pagedir, virt, ump_blocks[i].addr, ++ ump_blocks[i].size, prop); ++ ++ offset += ump_blocks[i].size; ++ } ++ ++ if (descriptor->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) { ++ u32 virt = descriptor->mali_mapping.addr + offset; ++ ++ /* Map in an extra virtual guard page at the end of the VMA */ ++ MALI_DEBUG_PRINT(6, ("Mapping in extra guard page\n")); ++ ++ mali_mmu_pagedir_update(pagedir, virt, ump_blocks[0].addr, _MALI_OSK_MALI_PAGE_SIZE, prop); ++ ++ offset += _MALI_OSK_MALI_PAGE_SIZE; ++ } ++ ++ _mali_osk_free(ump_blocks); ++ ++ return 0; ++} ++ ++void mali_ump_unmap(struct mali_session_data *session, mali_mem_allocation *descriptor) ++{ ++ ump_dd_handle ump_mem; ++ struct mali_page_directory *pagedir; ++ ++ ump_mem = descriptor->ump_mem.handle; ++ pagedir = session->page_directory; ++ ++ MALI_DEBUG_ASSERT(UMP_DD_HANDLE_INVALID != ump_mem); ++ ++ mali_mem_mali_map_free(descriptor); ++ ++ ump_dd_reference_release(ump_mem); ++ return; ++} ++ ++_mali_osk_errcode_t _mali_ukk_attach_ump_mem(_mali_uk_attach_ump_mem_s *args) ++{ ++ ump_dd_handle ump_mem; ++ struct mali_session_data *session; ++ mali_mem_allocation *descriptor; ++ int md, ret; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session = (struct mali_session_data *)args->ctx; ++ MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ /* check arguments */ ++ /* NULL might be a valid Mali address */ ++ if (!args->size) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); ++ ++ /* size must be a multiple of the system page size */ ++ if (args->size % _MALI_OSK_MALI_PAGE_SIZE) MALI_ERROR(_MALI_OSK_ERR_INVALID_ARGS); ++ ++ MALI_DEBUG_PRINT(3, ++ ("Requested to map ump memory with secure id %d into virtual memory 0x%08X, size 0x%08X\n", ++ args->secure_id, args->mali_address, args->size)); ++ ++ ump_mem = ump_dd_handle_create_from_secure_id((int)args->secure_id); ++ ++ if (UMP_DD_HANDLE_INVALID == ump_mem) MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ ++ descriptor = mali_mem_descriptor_create(session, MALI_MEM_UMP); ++ if (NULL == descriptor) { ++ ump_dd_reference_release(ump_mem); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ descriptor->ump_mem.handle = ump_mem; ++ descriptor->mali_mapping.addr = args->mali_address; ++ descriptor->size = args->size; ++ descriptor->mali_mapping.properties = MALI_MMU_FLAGS_DEFAULT; ++ descriptor->flags |= MALI_MEM_FLAG_DONT_CPU_MAP; ++ ++ if (args->flags & _MALI_MAP_EXTERNAL_MAP_GUARD_PAGE) { ++ descriptor->flags = MALI_MEM_FLAG_MALI_GUARD_PAGE; ++ } ++ ++ _mali_osk_mutex_wait(session->memory_lock); ++ ++ ret = mali_ump_map(session, descriptor); ++ if (0 != ret) { ++ _mali_osk_mutex_signal(session->memory_lock); ++ ump_dd_reference_release(ump_mem); ++ mali_mem_descriptor_destroy(descriptor); ++ MALI_ERROR(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_allocate_mapping(session->descriptor_mapping, descriptor, &md)) { ++ ump_dd_reference_release(ump_mem); ++ mali_mem_descriptor_destroy(descriptor); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ args->cookie = md; ++ ++ MALI_DEBUG_PRINT(5,("Returning from UMP attach\n")); ++ ++ MALI_SUCCESS; ++} ++ ++void mali_mem_ump_release(mali_mem_allocation *descriptor) ++{ ++ struct mali_session_data *session = descriptor->session; ++ ++ MALI_DEBUG_ASSERT(MALI_MEM_UMP == descriptor->type); ++ ++ mali_ump_unmap(session, descriptor); ++} ++ ++_mali_osk_errcode_t _mali_ukk_release_ump_mem(_mali_uk_release_ump_mem_s *args) ++{ ++ mali_mem_allocation * descriptor; ++ struct mali_session_data *session; ++ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ MALI_CHECK_NON_NULL(args->ctx, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ session = (struct mali_session_data *)args->ctx; ++ MALI_CHECK_NON_NULL(session, _MALI_OSK_ERR_INVALID_ARGS); ++ ++ if (_MALI_OSK_ERR_OK != mali_descriptor_mapping_get(session->descriptor_mapping, args->cookie, (void**)&descriptor)) { ++ MALI_DEBUG_PRINT(1, ("Invalid memory descriptor %d used to release ump memory\n", args->cookie)); ++ MALI_ERROR(_MALI_OSK_ERR_FAULT); ++ } ++ ++ descriptor = mali_descriptor_mapping_free(session->descriptor_mapping, args->cookie); ++ ++ if (NULL != descriptor) { ++ _mali_osk_mutex_wait(session->memory_lock); ++ mali_mem_ump_release(descriptor); ++ _mali_osk_mutex_signal(session->memory_lock); ++ ++ mali_mem_descriptor_destroy(descriptor); ++ } ++ ++ MALI_SUCCESS; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_atomics.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_atomics.c +new file mode 100644 +index 0000000..7b34ee2 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_atomics.c +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_atomics.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk.h" ++#include ++#include "mali_kernel_common.h" ++ ++void _mali_osk_atomic_dec( _mali_osk_atomic_t *atom ) ++{ ++ atomic_dec((atomic_t *)&atom->u.val); ++} ++ ++u32 _mali_osk_atomic_dec_return( _mali_osk_atomic_t *atom ) ++{ ++ return atomic_dec_return((atomic_t *)&atom->u.val); ++} ++ ++void _mali_osk_atomic_inc( _mali_osk_atomic_t *atom ) ++{ ++ atomic_inc((atomic_t *)&atom->u.val); ++} ++ ++u32 _mali_osk_atomic_inc_return( _mali_osk_atomic_t *atom ) ++{ ++ return atomic_inc_return((atomic_t *)&atom->u.val); ++} ++ ++_mali_osk_errcode_t _mali_osk_atomic_init( _mali_osk_atomic_t *atom, u32 val ) ++{ ++ MALI_CHECK_NON_NULL(atom, _MALI_OSK_ERR_INVALID_ARGS); ++ atomic_set((atomic_t *)&atom->u.val, val); ++ return _MALI_OSK_ERR_OK; ++} ++ ++u32 _mali_osk_atomic_read( _mali_osk_atomic_t *atom ) ++{ ++ return atomic_read((atomic_t *)&atom->u.val); ++} ++ ++void _mali_osk_atomic_term( _mali_osk_atomic_t *atom ) ++{ ++ MALI_IGNORE(atom); ++} ++ ++u32 _mali_osk_atomic_xchg( _mali_osk_atomic_t *atom, u32 val ) ++{ ++ return atomic_xchg((atomic_t*)&atom->u.val, val); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_irq.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_irq.c +new file mode 100644 +index 0000000..3576599 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_irq.c +@@ -0,0 +1,204 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_irq.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include /* For memory allocation */ ++#include ++#include ++#include ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++typedef struct _mali_osk_irq_t_struct { ++ u32 irqnum; ++ void *data; ++ _mali_osk_irq_uhandler_t uhandler; ++} mali_osk_irq_object_t; ++ ++typedef irqreturn_t (*irq_handler_func_t)(int, void *, struct pt_regs *); ++static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ); /* , struct pt_regs *regs*/ ++ ++#if defined(DEBUG) ++#if 0 ++ ++struct test_interrupt_data { ++ _mali_osk_irq_ack_t ack_func; ++ void *probe_data; ++ mali_bool interrupt_received; ++ wait_queue_head_t wq; ++}; ++ ++static irqreturn_t test_interrupt_upper_half(int port_name, void *dev_id) ++{ ++ irqreturn_t ret = IRQ_NONE; ++ struct test_interrupt_data *data = (struct test_interrupt_data *)dev_id; ++ ++ if (_MALI_OSK_ERR_OK == data->ack_func(data->probe_data)) { ++ data->interrupt_received = MALI_TRUE; ++ wake_up(&data->wq); ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} ++ ++static _mali_osk_errcode_t test_interrupt(u32 irqnum, ++ _mali_osk_irq_trigger_t trigger_func, ++ _mali_osk_irq_ack_t ack_func, ++ void *probe_data, ++ const char *description) ++{ ++ unsigned long irq_flags = 0; ++ struct test_interrupt_data data = { ++ .ack_func = ack_func, ++ .probe_data = probe_data, ++ .interrupt_received = MALI_FALSE, ++ }; ++ ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ irq_flags |= IRQF_SHARED; ++#endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */ ++ ++ if (0 != request_irq(irqnum, test_interrupt_upper_half, irq_flags, description, &data)) { ++ MALI_DEBUG_PRINT(2, ("Unable to install test IRQ handler for core '%s'\n", description)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ init_waitqueue_head(&data.wq); ++ ++ trigger_func(probe_data); ++ wait_event_timeout(data.wq, data.interrupt_received, 100); ++ ++ free_irq(irqnum, &data); ++ ++ if (data.interrupt_received) { ++ MALI_DEBUG_PRINT(3, ("%s: Interrupt test OK\n", description)); ++ return _MALI_OSK_ERR_OK; ++ } else { ++ MALI_PRINT_ERROR(("%s: Failed interrupt test on %u\n", description, irqnum)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++} ++#endif ++ ++#endif /* defined(DEBUG) */ ++ ++_mali_osk_irq_t *_mali_osk_irq_init( u32 irqnum, _mali_osk_irq_uhandler_t uhandler, void *int_data, _mali_osk_irq_trigger_t trigger_func, _mali_osk_irq_ack_t ack_func, void *probe_data, const char *description ) ++{ ++ mali_osk_irq_object_t *irq_object; ++ unsigned long irq_flags = 0; ++ ++#if defined(CONFIG_MALI_SHARED_INTERRUPTS) ++ irq_flags |= IRQF_SHARED; ++#endif /* defined(CONFIG_MALI_SHARED_INTERRUPTS) */ ++ ++ irq_object = kmalloc(sizeof(mali_osk_irq_object_t), GFP_KERNEL); ++ if (NULL == irq_object) { ++ return NULL; ++ } ++ ++ if (-1 == irqnum) { ++ /* Probe for IRQ */ ++ if ( (NULL != trigger_func) && (NULL != ack_func) ) { ++ unsigned long probe_count = 3; ++ _mali_osk_errcode_t err; ++ int irq; ++ ++ MALI_DEBUG_PRINT(2, ("Probing for irq\n")); ++ ++ do { ++ unsigned long mask; ++ ++ mask = probe_irq_on(); ++ trigger_func(probe_data); ++ ++ _mali_osk_time_ubusydelay(5); ++ ++ irq = probe_irq_off(mask); ++ err = ack_func(probe_data); ++ } while (irq < 0 && (err == _MALI_OSK_ERR_OK) && probe_count--); ++ ++ if (irq < 0 || (_MALI_OSK_ERR_OK != err)) irqnum = -1; ++ else irqnum = irq; ++ } else irqnum = -1; /* no probe functions, fault */ ++ ++ if (-1 != irqnum) { ++ /* found an irq */ ++ MALI_DEBUG_PRINT(2, ("Found irq %d\n", irqnum)); ++ } else { ++ MALI_DEBUG_PRINT(2, ("Probe for irq failed\n")); ++ } ++ } ++ ++ irq_object->irqnum = irqnum; ++ irq_object->uhandler = uhandler; ++ irq_object->data = int_data; ++ ++ if (-1 == irqnum) { ++ MALI_DEBUG_PRINT(2, ("No IRQ for core '%s' found during probe\n", description)); ++ kfree(irq_object); ++ return NULL; ++ } ++ ++#if defined(DEBUG) ++#if 0 ++ /* Verify that the configured interrupt settings are working */ ++ if (_MALI_OSK_ERR_OK != test_interrupt(irqnum, trigger_func, ack_func, probe_data, description)) { ++ MALI_DEBUG_PRINT(2, ("Test of IRQ handler for core '%s' failed\n", description)); ++ kfree(irq_object); ++ return NULL; ++ } ++#endif ++#endif ++ ++ if (0 != request_irq(irqnum, irq_handler_upper_half, irq_flags, description, irq_object)) { ++ MALI_DEBUG_PRINT(2, ("Unable to install IRQ handler for core '%s'\n", description)); ++ kfree(irq_object); ++ return NULL; ++ } ++ ++ return irq_object; ++} ++ ++void _mali_osk_irq_term( _mali_osk_irq_t *irq ) ++{ ++ mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)irq; ++ free_irq(irq_object->irqnum, irq_object); ++ kfree(irq_object); ++} ++ ++ ++/** This function is called directly in interrupt context from the OS just after ++ * the CPU get the hw-irq from mali, or other devices on the same IRQ-channel. ++ * It is registered one of these function for each mali core. When an interrupt ++ * arrives this function will be called equal times as registered mali cores. ++ * That means that we only check one mali core in one function call, and the ++ * core we check for each turn is given by the \a dev_id variable. ++ * If we detect an pending interrupt on the given core, we mask the interrupt ++ * out by settging the core's IRQ_MASK register to zero. ++ * Then we schedule the mali_core_irq_handler_bottom_half to run as high priority ++ * work queue job. ++ */ ++static irqreturn_t irq_handler_upper_half (int port_name, void* dev_id ) /* , struct pt_regs *regs*/ ++{ ++ irqreturn_t ret = IRQ_NONE; ++ mali_osk_irq_object_t *irq_object = (mali_osk_irq_object_t *)dev_id; ++ ++ if (_MALI_OSK_ERR_OK == irq_object->uhandler(irq_object->data)) { ++ ret = IRQ_HANDLED; ++ } ++ ++ return ret; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.c +new file mode 100644 +index 0000000..5ad3f98 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.c +@@ -0,0 +1,281 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_locks.c ++ * Implemenation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk_locks.h" ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++ ++ ++#ifdef DEBUG ++#ifdef LOCK_ORDER_CHECKING ++static DEFINE_SPINLOCK(lock_tracking_lock); ++static mali_bool add_lock_to_log_and_check(struct _mali_osk_lock_debug_s *lock, uint32_t tid); ++static void remove_lock_from_log(struct _mali_osk_lock_debug_s *lock, uint32_t tid); ++static const char * const lock_order_to_string(_mali_osk_lock_order_t order); ++#endif /* LOCK_ORDER_CHECKING */ ++ ++void _mali_osk_locks_debug_init(struct _mali_osk_lock_debug_s *checker, _mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order) ++{ ++ checker->orig_flags = flags; ++ checker->owner = 0; ++ ++#ifdef LOCK_ORDER_CHECKING ++ checker->order = order; ++ checker->next = NULL; ++#endif ++} ++ ++void _mali_osk_locks_debug_add(struct _mali_osk_lock_debug_s *checker) ++{ ++ checker->owner = _mali_osk_get_tid(); ++ ++#ifdef LOCK_ORDER_CHECKING ++ if (!(checker->orig_flags & _MALI_OSK_LOCKFLAG_UNORDERED)) { ++ if (!add_lock_to_log_and_check(checker, _mali_osk_get_tid())) { ++ printk(KERN_ERR "%d: ERROR lock %p taken while holding a lock of a higher order.\n", ++ _mali_osk_get_tid(), checker); ++ dump_stack(); ++ } ++ } ++#endif ++} ++ ++void _mali_osk_locks_debug_remove(struct _mali_osk_lock_debug_s *checker) ++{ ++ ++#ifdef LOCK_ORDER_CHECKING ++ if (!(checker->orig_flags & _MALI_OSK_LOCKFLAG_UNORDERED)) { ++ remove_lock_from_log(checker, _mali_osk_get_tid()); ++ } ++#endif ++ checker->owner = 0; ++} ++ ++ ++#ifdef LOCK_ORDER_CHECKING ++/* Lock order checking ++ * ------------------- ++ * ++ * To assure that lock ordering scheme defined by _mali_osk_lock_order_t is strictly adhered to, the ++ * following function will, together with a linked list and some extra members in _mali_osk_lock_debug_s, ++ * make sure that a lock that is taken has a higher order than the current highest-order lock a ++ * thread holds. ++ * ++ * This is done in the following manner: ++ * - A linked list keeps track of locks held by a thread. ++ * - A `next' pointer is added to each lock. This is used to chain the locks together. ++ * - When taking a lock, the `add_lock_to_log_and_check' makes sure that taking ++ * the given lock is legal. It will follow the linked list to find the last ++ * lock taken by this thread. If the last lock's order was lower than the ++ * lock that is to be taken, it appends the new lock to the list and returns ++ * true, if not, it return false. This return value is assert()'ed on in ++ * _mali_osk_lock_wait(). ++ */ ++ ++static struct _mali_osk_lock_debug_s *lock_lookup_list; ++ ++static void dump_lock_tracking_list(void) ++{ ++ struct _mali_osk_lock_debug_s *l; ++ u32 n = 1; ++ ++ /* print list for debugging purposes */ ++ l = lock_lookup_list; ++ ++ while (NULL != l) { ++ printk(" [lock: %p, tid_owner: %d, order: %d] ->", l, l->owner, l->order); ++ l = l->next; ++ MALI_DEBUG_ASSERT(n++ < 100); ++ } ++ printk(" NULL\n"); ++} ++ ++static int tracking_list_length(void) ++{ ++ struct _mali_osk_lock_debug_s *l; ++ u32 n = 0; ++ l = lock_lookup_list; ++ ++ while (NULL != l) { ++ l = l->next; ++ n++; ++ MALI_DEBUG_ASSERT(n < 100); ++ } ++ return n; ++} ++ ++static mali_bool add_lock_to_log_and_check(struct _mali_osk_lock_debug_s *lock, uint32_t tid) ++{ ++ mali_bool ret = MALI_FALSE; ++ _mali_osk_lock_order_t highest_order_for_tid = _MALI_OSK_LOCK_ORDER_FIRST; ++ struct _mali_osk_lock_debug_s *highest_order_lock = (struct _mali_osk_lock_debug_s *)0xbeefbabe; ++ struct _mali_osk_lock_debug_s *l; ++ unsigned long local_lock_flag; ++ u32 len; ++ ++ spin_lock_irqsave(&lock_tracking_lock, local_lock_flag); ++ len = tracking_list_length(); ++ ++ l = lock_lookup_list; ++ if (NULL == l) { /* This is the first lock taken by this thread -- record and return true */ ++ lock_lookup_list = lock; ++ spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag); ++ return MALI_TRUE; ++ } else { ++ /* Traverse the locks taken and find the lock of the highest order. ++ * Since several threads may hold locks, each lock's owner must be ++ * checked so that locks not owned by this thread can be ignored. */ ++ for(;;) { ++ MALI_DEBUG_ASSERT_POINTER( l ); ++ if (tid == l->owner && l->order >= highest_order_for_tid) { ++ highest_order_for_tid = l->order; ++ highest_order_lock = l; ++ } ++ ++ if (NULL != l->next) { ++ l = l->next; ++ } else { ++ break; ++ } ++ } ++ ++ l->next = lock; ++ l->next = NULL; ++ } ++ ++ /* We have now found the highest order lock currently held by this thread and can see if it is ++ * legal to take the requested lock. */ ++ ret = highest_order_for_tid < lock->order; ++ ++ if (!ret) { ++ printk(KERN_ERR "Took lock of order %d (%s) while holding lock of order %d (%s)\n", ++ lock->order, lock_order_to_string(lock->order), ++ highest_order_for_tid, lock_order_to_string(highest_order_for_tid)); ++ dump_lock_tracking_list(); ++ } ++ ++ if (len+1 != tracking_list_length()) { ++ printk(KERN_ERR "************ lock: %p\n", lock); ++ printk(KERN_ERR "************ before: %d *** after: %d ****\n", len, tracking_list_length()); ++ dump_lock_tracking_list(); ++ MALI_DEBUG_ASSERT_POINTER(NULL); ++ } ++ ++ spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag); ++ return ret; ++} ++ ++static void remove_lock_from_log(struct _mali_osk_lock_debug_s *lock, uint32_t tid) ++{ ++ struct _mali_osk_lock_debug_s *curr; ++ struct _mali_osk_lock_debug_s *prev = NULL; ++ unsigned long local_lock_flag; ++ u32 len; ++ u32 n = 0; ++ ++ spin_lock_irqsave(&lock_tracking_lock, local_lock_flag); ++ len = tracking_list_length(); ++ curr = lock_lookup_list; ++ ++ if (NULL == curr) { ++ printk(KERN_ERR "Error: Lock tracking list was empty on call to remove_lock_from_log\n"); ++ dump_lock_tracking_list(); ++ } ++ ++ MALI_DEBUG_ASSERT_POINTER(curr); ++ ++ ++ while (lock != curr) { ++ prev = curr; ++ ++ MALI_DEBUG_ASSERT_POINTER(curr); ++ curr = curr->next; ++ MALI_DEBUG_ASSERT(n++ < 100); ++ } ++ ++ if (NULL == prev) { ++ lock_lookup_list = curr->next; ++ } else { ++ MALI_DEBUG_ASSERT_POINTER(curr); ++ MALI_DEBUG_ASSERT_POINTER(prev); ++ prev->next = curr->next; ++ } ++ ++ lock->next = NULL; ++ ++ if (len-1 != tracking_list_length()) { ++ printk(KERN_ERR "************ lock: %p\n", lock); ++ printk(KERN_ERR "************ before: %d *** after: %d ****\n", len, tracking_list_length()); ++ dump_lock_tracking_list(); ++ MALI_DEBUG_ASSERT_POINTER(NULL); ++ } ++ ++ spin_unlock_irqrestore(&lock_tracking_lock, local_lock_flag); ++} ++ ++static const char * const lock_order_to_string(_mali_osk_lock_order_t order) ++{ ++ switch (order) { ++ case _MALI_OSK_LOCK_ORDER_SESSIONS: ++ return "_MALI_OSK_LOCK_ORDER_SESSIONS"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_MEM_SESSION: ++ return "_MALI_OSK_LOCK_ORDER_MEM_SESSION"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_MEM_INFO: ++ return "_MALI_OSK_LOCK_ORDER_MEM_INFO"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_MEM_PT_CACHE: ++ return "_MALI_OSK_LOCK_ORDER_MEM_PT_CACHE"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP: ++ return "_MALI_OSK_LOCK_ORDER_DESCRIPTOR_MAP"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_GROUP_VIRTUAL: ++ return "_MALI_OSK_LOCK_ORDER_GROUP_VIRTUAL"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_GROUP: ++ return "_MALI_OSK_LOCK_ORDER_GROUP"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_SCHEDULER: ++ return "_MALI_OSK_LOCK_ORDER_SCHEDULER"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_PM_CORE_STATE: ++ return "_MALI_OSK_LOCK_ORDER_PM_CORE_STATE"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_L2_COMMAND: ++ return "_MALI_OSK_LOCK_ORDER_L2_COMMAND"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_PROFILING: ++ return "_MALI_OSK_LOCK_ORDER_PROFILING"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_L2_COUNTER: ++ return "_MALI_OSK_LOCK_ORDER_L2_COUNTER"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_UTILIZATION: ++ return "_MALI_OSK_LOCK_ORDER_UTILIZATION"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_PM_EXECUTE: ++ return "_MALI_OSK_LOCK_ORDER_PM_EXECUTE"; ++ break; ++ case _MALI_OSK_LOCK_ORDER_SESSION_PENDING_JOBS: ++ return "_MALI_OSK_LOCK_ORDER_SESSION_PENDING_JOBS"; ++ break; ++ default: ++ return ""; ++ } ++} ++#endif /* LOCK_ORDER_CHECKING */ ++#endif /* DEBUG */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.h +new file mode 100644 +index 0000000..f5c45f7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_locks.h +@@ -0,0 +1,326 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_locks.h ++ * Defines OS abstraction of lock and mutex ++ */ ++#ifndef _MALI_OSK_LOCKS_H ++#define _MALI_OSK_LOCKS_H ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "mali_osk_types.h" ++ ++#ifdef _cplusplus ++extern "C" { ++#endif ++ ++ /* When DEBUG is enabled, this struct will be used to track owner, mode and order checking */ ++#ifdef DEBUG ++ struct _mali_osk_lock_debug_s { ++ u32 owner; ++ _mali_osk_lock_flags_t orig_flags; ++ _mali_osk_lock_order_t order; ++ struct _mali_osk_lock_debug_s *next; ++ }; ++#endif ++ ++ /* Anstraction of spinlock_t */ ++ struct _mali_osk_spinlock_s { ++#ifdef DEBUG ++ struct _mali_osk_lock_debug_s checker; ++#endif ++ spinlock_t spinlock; ++ }; ++ ++ /* Abstration of spinlock_t and lock flag which is used to store register's state before locking */ ++ struct _mali_osk_spinlock_irq_s { ++#ifdef DEBUG ++ struct _mali_osk_lock_debug_s checker; ++#endif ++ ++ spinlock_t spinlock; ++ unsigned long flags; ++ }; ++ ++ /* Abstraction of rw_semaphore in OS */ ++ struct _mali_osk_mutex_rw_s { ++#ifdef DEBUG ++ struct _mali_osk_lock_debug_s checker; ++ _mali_osk_lock_mode_t mode; ++#endif ++ ++ struct rw_semaphore rw_sema; ++ }; ++ ++ /* Mutex and mutex_interruptible functions share the same osk mutex struct */ ++ struct _mali_osk_mutex_s { ++#ifdef DEBUG ++ struct _mali_osk_lock_debug_s checker; ++#endif ++ struct mutex mutex; ++ }; ++ ++#ifdef DEBUG ++ /** @brief _mali_osk_locks_debug_init/add/remove() functions are declared when DEBUG is enabled and ++ * defined in file mali_osk_locks.c. When LOCK_ORDER_CHECKING is enabled, calling these functions when we ++ * init/lock/unlock a lock/mutex, we could track lock order of a given tid. */ ++ void _mali_osk_locks_debug_init(struct _mali_osk_lock_debug_s *checker, _mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order); ++ void _mali_osk_locks_debug_add(struct _mali_osk_lock_debug_s *checker); ++ void _mali_osk_locks_debug_remove(struct _mali_osk_lock_debug_s *checker); ++ ++ /** @brief This function can return a given lock's owner when DEBUG is enabled. */ ++ static inline u32 _mali_osk_lock_get_owner(struct _mali_osk_lock_debug_s *lock) ++ { ++ return lock->owner; ++ } ++#else ++#define _mali_osk_locks_debug_init(x, y, z) do {} while (0) ++#define _mali_osk_locks_debug_add(x) do {} while (0) ++#define _mali_osk_locks_debug_remove(x) do {} while (0) ++#endif ++ ++ /** @brief Before use _mali_osk_spin_lock, init function should be used to allocate memory and initial spinlock*/ ++ static inline _mali_osk_spinlock_t *_mali_osk_spinlock_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order) ++ { ++ _mali_osk_spinlock_t *lock = NULL; ++ ++ lock = kmalloc(sizeof(_mali_osk_spinlock_t), GFP_KERNEL); ++ if (NULL == lock) { ++ return NULL; ++ } ++ spin_lock_init(&lock->spinlock); ++ _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order); ++ return lock; ++ } ++ ++ /** @brief Lock a spinlock */ ++ static inline void _mali_osk_spinlock_lock(_mali_osk_spinlock_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ spin_lock(&lock->spinlock); ++ _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock); ++ } ++ ++ /** @brief Unlock a spinlock */ ++ static inline void _mali_osk_spinlock_unlock(_mali_osk_spinlock_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock); ++ spin_unlock(&lock->spinlock); ++ } ++ ++ /** @brief Free a memory block which the argument lock pointed to and its type must be ++ * _mali_osk_spinlock_t *. */ ++ static inline void _mali_osk_spinlock_term(_mali_osk_spinlock_t *lock) ++ { ++ /* Parameter validation */ ++ BUG_ON(NULL == lock); ++ ++ /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */ ++ kfree(lock); ++ } ++ ++ /** @brief Before _mali_osk_spinlock_irq_lock/unlock/term() is called, init function should be ++ * called to initial spinlock and flags in struct _mali_osk_spinlock_irq_t. */ ++ static inline _mali_osk_spinlock_irq_t *_mali_osk_spinlock_irq_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order) ++ { ++ _mali_osk_spinlock_irq_t *lock = NULL; ++ lock = kmalloc(sizeof(_mali_osk_spinlock_irq_t), GFP_KERNEL); ++ ++ if (NULL == lock) { ++ return NULL; ++ } ++ ++ lock->flags = 0; ++ spin_lock_init(&lock->spinlock); ++ _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order); ++ return lock; ++ } ++ ++ /** @brief Lock spinlock and save the register's state */ ++ static inline void _mali_osk_spinlock_irq_lock(_mali_osk_spinlock_irq_t *lock) ++ { ++ unsigned long tmp_flags; ++ ++ BUG_ON(NULL == lock); ++ spin_lock_irqsave(&lock->spinlock, tmp_flags); ++ lock->flags = tmp_flags; ++ _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock); ++ } ++ ++ /** @brief Unlock spinlock with saved register's state */ ++ static inline void _mali_osk_spinlock_irq_unlock(_mali_osk_spinlock_irq_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock); ++ spin_unlock_irqrestore(&lock->spinlock, lock->flags); ++ } ++ ++ /** @brief Destroy a given memory block which lock pointed to, and the lock type must be ++ * _mali_osk_spinlock_irq_t *. */ ++ static inline void _mali_osk_spinlock_irq_term(_mali_osk_spinlock_irq_t *lock) ++ { ++ /* Parameter validation */ ++ BUG_ON(NULL == lock); ++ ++ /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */ ++ kfree(lock); ++ } ++ ++ /** @brief Before _mali_osk_mutex_rw_wait/signal/term() is called, we should call ++ * _mali_osk_mutex_rw_init() to kmalloc a memory block and initial part of elements in it. */ ++ static inline _mali_osk_mutex_rw_t *_mali_osk_mutex_rw_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order) ++ { ++ _mali_osk_mutex_rw_t *lock = NULL; ++ ++ lock = kmalloc(sizeof(_mali_osk_mutex_rw_t), GFP_KERNEL); ++ ++ if (NULL == lock) { ++ return NULL; ++ } ++ ++ init_rwsem(&lock->rw_sema); ++ _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order); ++ return lock; ++ } ++ ++ /** @brief When call _mali_osk_mutex_rw_wait/signal() functions, the second argument mode ++ * should be assigned with value _MALI_OSK_LOCKMODE_RO or _MALI_OSK_LOCKMODE_RW */ ++ static inline void _mali_osk_mutex_rw_wait(_mali_osk_mutex_rw_t *lock, _mali_osk_lock_mode_t mode) ++ { ++ BUG_ON(NULL == lock); ++ BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode)); ++ ++ if (mode == _MALI_OSK_LOCKMODE_RO) { ++ down_read(&lock->rw_sema); ++ } else { ++ down_write(&lock->rw_sema); ++ } ++ ++#ifdef DEBUG ++ if (mode == _MALI_OSK_LOCKMODE_RW) { ++ lock->mode = mode; ++ } else { /* mode == _MALI_OSK_LOCKMODE_RO */ ++ lock->mode = mode; ++ } ++ _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock); ++#endif ++ } ++ ++ /** @brief Up lock->rw_sema with up_read/write() accordinf argument mode's value. */ ++ static inline void _mali_osk_mutex_rw_signal(_mali_osk_mutex_rw_t *lock, _mali_osk_lock_mode_t mode) ++ { ++ BUG_ON(NULL == lock); ++ BUG_ON(!(_MALI_OSK_LOCKMODE_RO == mode || _MALI_OSK_LOCKMODE_RW == mode)); ++#ifdef DEBUG ++ /* make sure the thread releasing the lock actually was the owner */ ++ if (mode == _MALI_OSK_LOCKMODE_RW) { ++ _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock); ++ /* This lock now has no owner */ ++ lock->checker.owner = 0; ++ } ++#endif ++ ++ if (mode == _MALI_OSK_LOCKMODE_RO) { ++ up_read(&lock->rw_sema); ++ } else { ++ up_write(&lock->rw_sema); ++ } ++ } ++ ++ /** @brief Free a given memory block which lock pointed to and its type must be ++ * _mali_sok_mutex_rw_t *. */ ++ static inline void _mali_osk_mutex_rw_term(_mali_osk_mutex_rw_t *lock) ++ { ++ /* Parameter validation */ ++ BUG_ON(NULL == lock); ++ ++ /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */ ++ kfree(lock); ++ } ++ ++ /** @brief Mutex & mutex_interruptible share the same init and term function, because they have the ++ * same osk mutex struct, and the difference between them is which locking function they use */ ++ static inline _mali_osk_mutex_t *_mali_osk_mutex_init(_mali_osk_lock_flags_t flags, _mali_osk_lock_order_t order) ++ { ++ _mali_osk_mutex_t *lock = NULL; ++ ++ lock = kmalloc(sizeof(_mali_osk_mutex_t), GFP_KERNEL); ++ ++ if (NULL == lock) { ++ return NULL; ++ } ++ mutex_init(&lock->mutex); ++ ++ _mali_osk_locks_debug_init((struct _mali_osk_lock_debug_s *)lock, flags, order); ++ return lock; ++ } ++ ++ /** @brief Lock the lock->mutex with mutex_lock_interruptible function */ ++ static inline _mali_osk_errcode_t _mali_osk_mutex_wait_interruptible(_mali_osk_mutex_t *lock) ++ { ++ _mali_osk_errcode_t err = _MALI_OSK_ERR_OK; ++ ++ BUG_ON(NULL == lock); ++ ++ if (mutex_lock_interruptible(&lock->mutex)) { ++ printk(KERN_WARNING "Mali: Can not lock mutex\n"); ++ err = _MALI_OSK_ERR_RESTARTSYSCALL; ++ } ++ ++ _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock); ++ return err; ++ } ++ ++ /** @brief Unlock the lock->mutex which is locked with mutex_lock_interruptible() function. */ ++ static inline void _mali_osk_mutex_signal_interruptible(_mali_osk_mutex_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock); ++ mutex_unlock(&lock->mutex); ++ } ++ ++ /** @brief Lock the lock->mutex just with mutex_lock() function which could not be interruptted. */ ++ static inline void _mali_osk_mutex_wait(_mali_osk_mutex_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ mutex_lock(&lock->mutex); ++ _mali_osk_locks_debug_add((struct _mali_osk_lock_debug_s *)lock); ++ } ++ ++ /** @brief Unlock the lock->mutex which is locked with mutex_lock() function. */ ++ static inline void _mali_osk_mutex_signal(_mali_osk_mutex_t *lock) ++ { ++ BUG_ON(NULL == lock); ++ _mali_osk_locks_debug_remove((struct _mali_osk_lock_debug_s *)lock); ++ mutex_unlock(&lock->mutex); ++ } ++ ++ /** @brief Free a given memory block which lock point. */ ++ static inline void _mali_osk_mutex_term(_mali_osk_mutex_t *lock) ++ { ++ /* Parameter validation */ ++ BUG_ON(NULL == lock); ++ ++ /* Linux requires no explicit termination of spinlocks, semaphores, or rw_semaphores */ ++ kfree(lock); ++ } ++ ++#ifdef _cplusplus ++} ++#endif ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_low_level_mem.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_low_level_mem.c +new file mode 100644 +index 0000000..2fa7b1a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_low_level_mem.c +@@ -0,0 +1,137 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_low_level_mem.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include ++#include ++#include ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_ukk.h" ++ ++void _mali_osk_mem_barrier( void ) ++{ ++ mb(); ++} ++ ++void _mali_osk_write_mem_barrier( void ) ++{ ++ wmb(); ++} ++ ++mali_io_address _mali_osk_mem_mapioregion( u32 phys, u32 size, const char *description ) ++{ ++ return (mali_io_address)ioremap_nocache(phys, size); ++} ++ ++void _mali_osk_mem_unmapioregion( u32 phys, u32 size, mali_io_address virt ) ++{ ++ iounmap((void*)virt); ++} ++ ++_mali_osk_errcode_t inline _mali_osk_mem_reqregion( u32 phys, u32 size, const char *description ) ++{ ++#if MALI_LICENSE_IS_GPL ++ return _MALI_OSK_ERR_OK; /* GPL driver gets the mem region for the resources registered automatically */ ++#else ++ return ((NULL == request_mem_region(phys, size, description)) ? _MALI_OSK_ERR_NOMEM : _MALI_OSK_ERR_OK); ++#endif ++} ++ ++void inline _mali_osk_mem_unreqregion( u32 phys, u32 size ) ++{ ++#if !MALI_LICENSE_IS_GPL ++ release_mem_region(phys, size); ++#endif ++} ++ ++void inline _mali_osk_mem_iowrite32_relaxed( volatile mali_io_address addr, u32 offset, u32 val ) ++{ ++ __raw_writel(cpu_to_le32(val),((u8*)addr) + offset); ++} ++ ++u32 inline _mali_osk_mem_ioread32( volatile mali_io_address addr, u32 offset ) ++{ ++ return ioread32(((u8*)addr) + offset); ++} ++ ++void inline _mali_osk_mem_iowrite32( volatile mali_io_address addr, u32 offset, u32 val ) ++{ ++ iowrite32(val, ((u8*)addr) + offset); ++} ++ ++void _mali_osk_cache_flushall( void ) ++{ ++ /** @note Cached memory is not currently supported in this implementation */ ++} ++ ++void _mali_osk_cache_ensure_uncached_range_flushed( void *uncached_mapping, u32 offset, u32 size ) ++{ ++ _mali_osk_write_mem_barrier(); ++} ++ ++u32 _mali_osk_mem_write_safe(void *dest, const void *src, u32 size) ++{ ++#define MALI_MEM_SAFE_COPY_BLOCK_SIZE 4096 ++ u32 retval = 0; ++ void *temp_buf; ++ ++ temp_buf = kmalloc(MALI_MEM_SAFE_COPY_BLOCK_SIZE, GFP_KERNEL); ++ if (NULL != temp_buf) { ++ u32 bytes_left_to_copy = size; ++ u32 i; ++ for (i = 0; i < size; i += MALI_MEM_SAFE_COPY_BLOCK_SIZE) { ++ u32 size_to_copy; ++ u32 size_copied; ++ u32 bytes_left; ++ ++ if (bytes_left_to_copy > MALI_MEM_SAFE_COPY_BLOCK_SIZE) { ++ size_to_copy = MALI_MEM_SAFE_COPY_BLOCK_SIZE; ++ } else { ++ size_to_copy = bytes_left_to_copy; ++ } ++ ++ bytes_left = copy_from_user(temp_buf, ((char*)src) + i, size_to_copy); ++ size_copied = size_to_copy - bytes_left; ++ ++ bytes_left = copy_to_user(((char*)dest) + i, temp_buf, size_copied); ++ size_copied -= bytes_left; ++ ++ bytes_left_to_copy -= size_copied; ++ retval += size_copied; ++ ++ if (size_copied != size_to_copy) { ++ break; /* Early out, we was not able to copy this entire block */ ++ } ++ } ++ ++ kfree(temp_buf); ++ } ++ ++ return retval; ++} ++ ++_mali_osk_errcode_t _mali_ukk_mem_write_safe(_mali_uk_mem_write_safe_s *args) ++{ ++ MALI_DEBUG_ASSERT_POINTER(args); ++ ++ if (NULL == args->ctx) { ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ /* Return number of bytes actually copied */ ++ args->size = _mali_osk_mem_write_safe(args->dest, args->src, args->size); ++ return _MALI_OSK_ERR_OK; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_mali.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_mali.c +new file mode 100644 +index 0000000..626c35f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_mali.c +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_mali.c ++ * Implementation of the OS abstraction layer which is specific for the Mali kernel device driver ++ */ ++#include ++#include ++#include ++#include ++ ++#include "mali_osk_mali.h" ++#include "mali_kernel_common.h" /* MALI_xxx macros */ ++#include "mali_osk.h" /* kernel side OS functions */ ++#include "mali_kernel_linux.h" ++ ++_mali_osk_errcode_t _mali_osk_resource_find(u32 addr, _mali_osk_resource_t *res) ++{ ++ int i; ++ ++ if (NULL == mali_platform_device) { ++ /* Not connected to a device */ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ } ++ ++ for (i = 0; i < mali_platform_device->num_resources; i++) { ++ if (IORESOURCE_MEM == resource_type(&(mali_platform_device->resource[i])) && ++ mali_platform_device->resource[i].start == addr) { ++ if (NULL != res) { ++ res->base = addr; ++ res->description = mali_platform_device->resource[i].name; ++ ++ /* Any (optional) IRQ resource belonging to this resource will follow */ ++ if ((i + 1) < mali_platform_device->num_resources && ++ IORESOURCE_IRQ == resource_type(&(mali_platform_device->resource[i+1]))) { ++ res->irq = mali_platform_device->resource[i+1].start; ++ } else { ++ res->irq = -1; ++ } ++ } ++ return _MALI_OSK_ERR_OK; ++ } ++ } ++ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++} ++ ++u32 _mali_osk_resource_base_address(void) ++{ ++ u32 lowest_addr = 0xFFFFFFFF; ++ u32 ret = 0; ++ ++ if (NULL != mali_platform_device) { ++ int i; ++ for (i = 0; i < mali_platform_device->num_resources; i++) { ++ if (mali_platform_device->resource[i].flags & IORESOURCE_MEM && ++ mali_platform_device->resource[i].start < lowest_addr) { ++ lowest_addr = mali_platform_device->resource[i].start; ++ ret = lowest_addr; ++ } ++ } ++ } ++ ++ return ret; ++} ++ ++_mali_osk_errcode_t _mali_osk_device_data_get(struct _mali_osk_device_data *data) ++{ ++ MALI_DEBUG_ASSERT_POINTER(data); ++ ++ if (NULL != mali_platform_device) { ++ struct mali_gpu_device_data* os_data = NULL; ++ ++ os_data = (struct mali_gpu_device_data*)mali_platform_device->dev.platform_data; ++ if (NULL != os_data) { ++ /* Copy data from OS dependant struct to Mali neutral struct (identical!) */ ++ data->dedicated_mem_start = os_data->dedicated_mem_start; ++ data->dedicated_mem_size = os_data->dedicated_mem_size; ++ data->shared_mem_size = os_data->shared_mem_size; ++ data->fb_start = os_data->fb_start; ++ data->fb_size = os_data->fb_size; ++ data->max_job_runtime = os_data->max_job_runtime; ++ data->utilization_interval = os_data->utilization_interval; ++ data->utilization_callback = os_data->utilization_callback; ++ data->pmu_switch_delay = os_data->pmu_switch_delay; ++ data->set_freq_callback = os_data->set_freq_callback; ++ ++ memcpy(data->pmu_domain_config, os_data->pmu_domain_config, sizeof(os_data->pmu_domain_config)); ++ return _MALI_OSK_ERR_OK; ++ } ++ } ++ ++ return _MALI_OSK_ERR_ITEM_NOT_FOUND; ++} ++ ++mali_bool _mali_osk_shared_interrupts(void) ++{ ++ u32 irqs[128]; ++ u32 i, j, irq, num_irqs_found = 0; ++ ++ MALI_DEBUG_ASSERT_POINTER(mali_platform_device); ++ MALI_DEBUG_ASSERT(128 >= mali_platform_device->num_resources); ++ ++ for (i = 0; i < mali_platform_device->num_resources; i++) { ++ if (IORESOURCE_IRQ & mali_platform_device->resource[i].flags) { ++ irq = mali_platform_device->resource[i].start; ++ ++ for (j = 0; j < num_irqs_found; ++j) { ++ if (irq == irqs[j]) { ++ return MALI_TRUE; ++ } ++ } ++ ++ irqs[num_irqs_found++] = irq; ++ } ++ } ++ ++ return MALI_FALSE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_math.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_math.c +new file mode 100644 +index 0000000..c097fcc +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_math.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_math.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk.h" ++#include ++ ++u32 _mali_osk_clz( u32 input ) ++{ ++ return 32-fls(input); ++} ++ ++u32 _mali_osk_fls( u32 input ) ++{ ++ return fls(input); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_memory.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_memory.c +new file mode 100644 +index 0000000..64d8951 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_memory.c +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_memory.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk.h" ++#include ++#include ++ ++void inline *_mali_osk_calloc( u32 n, u32 size ) ++{ ++ return kcalloc(n, size, GFP_KERNEL); ++} ++ ++void inline *_mali_osk_malloc( u32 size ) ++{ ++ return kmalloc(size, GFP_KERNEL); ++} ++ ++void inline _mali_osk_free( void *ptr ) ++{ ++ kfree(ptr); ++} ++ ++void inline *_mali_osk_valloc( u32 size ) ++{ ++ return vmalloc(size); ++} ++ ++void inline _mali_osk_vfree( void *ptr ) ++{ ++ vfree(ptr); ++} ++ ++void inline *_mali_osk_memcpy( void *dst, const void *src, u32 len ) ++{ ++ return memcpy(dst, src, len); ++} ++ ++void inline *_mali_osk_memset( void *s, u32 c, u32 n ) ++{ ++ return memset(s, c, n); ++} ++ ++mali_bool _mali_osk_mem_check_allocated( u32 max_allocated ) ++{ ++ /* No need to prevent an out-of-memory dialogue appearing on Linux, ++ * so we always return MALI_TRUE. ++ */ ++ return MALI_TRUE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_misc.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_misc.c +new file mode 100644 +index 0000000..28ea90a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_misc.c +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_misc.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++#include ++#include ++#include ++#include ++#include ++#include "mali_osk.h" ++ ++void _mali_osk_dbgmsg( const char *fmt, ... ) ++{ ++ va_list args; ++ va_start(args, fmt); ++ vprintk(fmt, args); ++ va_end(args); ++} ++ ++u32 _mali_osk_snprintf( char *buf, u32 size, const char *fmt, ... ) ++{ ++ int res; ++ va_list args; ++ va_start(args, fmt); ++ ++ res = vscnprintf(buf, (size_t)size, fmt, args); ++ ++ va_end(args); ++ return res; ++} ++ ++void _mali_osk_abort(void) ++{ ++ /* make a simple fault by dereferencing a NULL pointer */ ++ dump_stack(); ++ *(int *)0 = 0; ++} ++ ++void _mali_osk_break(void) ++{ ++ _mali_osk_abort(); ++} ++ ++u32 _mali_osk_get_pid(void) ++{ ++ /* Thread group ID is the process ID on Linux */ ++ return (u32)current->tgid; ++} ++ ++u32 _mali_osk_get_tid(void) ++{ ++ /* pid is actually identifying the thread on Linux */ ++ u32 tid = current->pid; ++ ++ /* If the pid is 0 the core was idle. Instead of returning 0 we return a special number ++ * identifying which core we are on. */ ++ if (0 == tid) { ++ tid = -(1 + raw_smp_processor_id()); ++ } ++ ++ return tid; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_notification.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_notification.c +new file mode 100644 +index 0000000..3738ad3 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_notification.c +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_notification.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++#include ++#include ++#include ++ ++/** ++ * Declaration of the notification queue object type ++ * Contains a linked list of notification pending delivery to user space. ++ * It also contains a wait queue of exclusive waiters blocked in the ioctl ++ * When a new notification is posted a single thread is resumed. ++ */ ++struct _mali_osk_notification_queue_t_struct { ++ spinlock_t mutex; /**< Mutex protecting the list */ ++ wait_queue_head_t receive_queue; /**< Threads waiting for new entries to the queue */ ++ struct list_head head; /**< List of notifications waiting to be picked up */ ++}; ++ ++typedef struct _mali_osk_notification_wrapper_t_struct { ++ struct list_head list; /**< Internal linked list variable */ ++ _mali_osk_notification_t data; /**< Notification data */ ++} _mali_osk_notification_wrapper_t; ++ ++_mali_osk_notification_queue_t *_mali_osk_notification_queue_init( void ) ++{ ++ _mali_osk_notification_queue_t * result; ++ ++ result = (_mali_osk_notification_queue_t *)kmalloc(sizeof(_mali_osk_notification_queue_t), GFP_KERNEL); ++ if (NULL == result) return NULL; ++ ++ spin_lock_init(&result->mutex); ++ init_waitqueue_head(&result->receive_queue); ++ INIT_LIST_HEAD(&result->head); ++ ++ return result; ++} ++ ++_mali_osk_notification_t *_mali_osk_notification_create( u32 type, u32 size ) ++{ ++ /* OPT Recycling of notification objects */ ++ _mali_osk_notification_wrapper_t *notification; ++ ++ notification = (_mali_osk_notification_wrapper_t *)kmalloc( sizeof(_mali_osk_notification_wrapper_t) + size, ++ GFP_KERNEL | __GFP_HIGH | __GFP_REPEAT); ++ if (NULL == notification) { ++ MALI_DEBUG_PRINT(1, ("Failed to create a notification object\n")); ++ return NULL; ++ } ++ ++ /* Init the list */ ++ INIT_LIST_HEAD(¬ification->list); ++ ++ if (0 != size) { ++ notification->data.result_buffer = ((u8*)notification) + sizeof(_mali_osk_notification_wrapper_t); ++ } else { ++ notification->data.result_buffer = NULL; ++ } ++ ++ /* set up the non-allocating fields */ ++ notification->data.notification_type = type; ++ notification->data.result_buffer_size = size; ++ ++ /* all ok */ ++ return &(notification->data); ++} ++ ++void _mali_osk_notification_delete( _mali_osk_notification_t *object ) ++{ ++ _mali_osk_notification_wrapper_t *notification; ++ MALI_DEBUG_ASSERT_POINTER( object ); ++ ++ notification = container_of( object, _mali_osk_notification_wrapper_t, data ); ++ ++ /* Free the container */ ++ kfree(notification); ++} ++ ++void _mali_osk_notification_queue_term( _mali_osk_notification_queue_t *queue ) ++{ ++ _mali_osk_notification_t *result; ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ ++ while (_MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, &result)) { ++ _mali_osk_notification_delete( result ); ++ } ++ ++ /* not much to do, just free the memory */ ++ kfree(queue); ++} ++void _mali_osk_notification_queue_send( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t *object ) ++{ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ unsigned long irq_flags; ++#endif ++ ++ _mali_osk_notification_wrapper_t *notification; ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ MALI_DEBUG_ASSERT_POINTER( object ); ++ ++ notification = container_of( object, _mali_osk_notification_wrapper_t, data ); ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ spin_lock_irqsave(&queue->mutex, irq_flags); ++#else ++ spin_lock(&queue->mutex); ++#endif ++ ++ list_add_tail(¬ification->list, &queue->head); ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ spin_unlock_irqrestore(&queue->mutex, irq_flags); ++#else ++ spin_unlock(&queue->mutex); ++#endif ++ ++ /* and wake up one possible exclusive waiter */ ++ wake_up(&queue->receive_queue); ++} ++ ++_mali_osk_errcode_t _mali_osk_notification_queue_dequeue( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result ) ++{ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ unsigned long irq_flags; ++#endif ++ ++ _mali_osk_errcode_t ret = _MALI_OSK_ERR_ITEM_NOT_FOUND; ++ _mali_osk_notification_wrapper_t *wrapper_object; ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ spin_lock_irqsave(&queue->mutex, irq_flags); ++#else ++ spin_lock(&queue->mutex); ++#endif ++ ++ if (!list_empty(&queue->head)) { ++ wrapper_object = list_entry(queue->head.next, _mali_osk_notification_wrapper_t, list); ++ *result = &(wrapper_object->data); ++ list_del_init(&wrapper_object->list); ++ ret = _MALI_OSK_ERR_OK; ++ } ++ ++#if defined(MALI_UPPER_HALF_SCHEDULING) ++ spin_unlock_irqrestore(&queue->mutex, irq_flags); ++#else ++ spin_unlock(&queue->mutex); ++#endif ++ ++ return ret; ++} ++ ++_mali_osk_errcode_t _mali_osk_notification_queue_receive( _mali_osk_notification_queue_t *queue, _mali_osk_notification_t **result ) ++{ ++ /* check input */ ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ MALI_DEBUG_ASSERT_POINTER( result ); ++ ++ /* default result */ ++ *result = NULL; ++ ++ if (wait_event_interruptible(queue->receive_queue, ++ _MALI_OSK_ERR_OK == _mali_osk_notification_queue_dequeue(queue, result))) { ++ return _MALI_OSK_ERR_RESTARTSYSCALL; ++ } ++ ++ return _MALI_OSK_ERR_OK; /* all ok */ ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_pm.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_pm.c +new file mode 100644 +index 0000000..f8769b1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_pm.c +@@ -0,0 +1,109 @@ ++/** ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_pm.c ++ * Implementation of the callback functions from common power management ++ */ ++ ++#include ++ ++#ifdef CONFIG_PM_RUNTIME ++#include ++#endif /* CONFIG_PM_RUNTIME */ ++#include ++#include ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_kernel_linux.h" ++ ++static _mali_osk_atomic_t mali_pm_ref_count; ++ ++void _mali_osk_pm_dev_enable(void) ++{ ++ _mali_osk_atomic_init(&mali_pm_ref_count, 0); ++} ++ ++void _mali_osk_pm_dev_disable(void) ++{ ++ _mali_osk_atomic_term(&mali_pm_ref_count); ++} ++ ++/* Can NOT run in atomic context */ ++_mali_osk_errcode_t _mali_osk_pm_dev_ref_add(void) ++{ ++#ifdef CONFIG_PM_RUNTIME ++ int err; ++ MALI_DEBUG_ASSERT_POINTER(mali_platform_device); ++ err = pm_runtime_get_sync(&(mali_platform_device->dev)); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pm_runtime_mark_last_busy(&(mali_platform_device->dev)); ++#endif ++ if (0 > err) { ++ MALI_PRINT_ERROR(("Mali OSK PM: pm_runtime_get_sync() returned error code %d\n", err)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ _mali_osk_atomic_inc(&mali_pm_ref_count); ++ MALI_DEBUG_PRINT(4, ("Mali OSK PM: Power ref taken (%u)\n", _mali_osk_atomic_read(&mali_pm_ref_count))); ++#endif ++ return _MALI_OSK_ERR_OK; ++} ++ ++/* Can run in atomic context */ ++void _mali_osk_pm_dev_ref_dec(void) ++{ ++#ifdef CONFIG_PM_RUNTIME ++ MALI_DEBUG_ASSERT_POINTER(mali_platform_device); ++ _mali_osk_atomic_dec(&mali_pm_ref_count); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pm_runtime_mark_last_busy(&(mali_platform_device->dev)); ++ pm_runtime_put_autosuspend(&(mali_platform_device->dev)); ++#else ++ pm_runtime_put(&(mali_platform_device->dev)); ++#endif ++ MALI_DEBUG_PRINT(4, ("Mali OSK PM: Power ref released (%u)\n", _mali_osk_atomic_read(&mali_pm_ref_count))); ++#endif ++} ++ ++/* Can run in atomic context */ ++mali_bool _mali_osk_pm_dev_ref_add_no_power_on(void) ++{ ++#ifdef CONFIG_PM_RUNTIME ++ u32 ref; ++ MALI_DEBUG_ASSERT_POINTER(mali_platform_device); ++ pm_runtime_get_noresume(&(mali_platform_device->dev)); ++ ref = _mali_osk_atomic_read(&mali_pm_ref_count); ++ MALI_DEBUG_PRINT(4, ("Mali OSK PM: No-power ref taken (%u)\n", _mali_osk_atomic_read(&mali_pm_ref_count))); ++ return ref > 0 ? MALI_TRUE : MALI_FALSE; ++#else ++ return MALI_TRUE; ++#endif ++} ++ ++/* Can run in atomic context */ ++void _mali_osk_pm_dev_ref_dec_no_power_on(void) ++{ ++#ifdef CONFIG_PM_RUNTIME ++ MALI_DEBUG_ASSERT_POINTER(mali_platform_device); ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pm_runtime_put_autosuspend(&(mali_platform_device->dev)); ++#else ++ pm_runtime_put(&(mali_platform_device->dev)); ++#endif ++ MALI_DEBUG_PRINT(4, ("Mali OSK PM: No-power ref released (%u)\n", _mali_osk_atomic_read(&mali_pm_ref_count))); ++#endif ++} ++ ++void _mali_osk_pm_dev_barrier(void) ++{ ++#ifdef CONFIG_PM_RUNTIME ++ pm_runtime_barrier(&(mali_platform_device->dev)); ++#endif ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_profiling.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_profiling.c +new file mode 100644 +index 0000000..0c1ff3b +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_profiling.c +@@ -0,0 +1,308 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++ ++#include ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_ukk.h" ++#include "mali_uk_types.h" ++#include "mali_osk_profiling.h" ++#include "mali_linux_trace.h" ++#include "mali_gp.h" ++#include "mali_pp.h" ++#include "mali_pp_scheduler.h" ++#include "mali_l2_cache.h" ++#include "mali_user_settings_db.h" ++ ++_mali_osk_errcode_t _mali_osk_profiling_init(mali_bool auto_start) ++{ ++ if (MALI_TRUE == auto_start) { ++ mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, MALI_TRUE); ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _mali_osk_profiling_term(void) ++{ ++ /* Nothing to do */ ++} ++ ++_mali_osk_errcode_t _mali_osk_profiling_start(u32 * limit) ++{ ++ /* Nothing to do */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_osk_profiling_stop(u32 *count) ++{ ++ /* Nothing to do */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++u32 _mali_osk_profiling_get_count(void) ++{ ++ return 0; ++} ++ ++_mali_osk_errcode_t _mali_osk_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) ++{ ++ /* Nothing to do */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_osk_profiling_clear(void) ++{ ++ /* Nothing to do */ ++ return _MALI_OSK_ERR_OK; ++} ++ ++mali_bool _mali_osk_profiling_is_recording(void) ++{ ++ return MALI_FALSE; ++} ++ ++mali_bool _mali_osk_profiling_have_recording(void) ++{ ++ return MALI_FALSE; ++} ++ ++void _mali_osk_profiling_report_sw_counters(u32 *counters) ++{ ++ trace_mali_sw_counters(_mali_osk_get_pid(), _mali_osk_get_tid(), NULL, counters); ++} ++ ++ ++_mali_osk_errcode_t _mali_ukk_profiling_start(_mali_uk_profiling_start_s *args) ++{ ++ return _mali_osk_profiling_start(&args->limit); ++} ++ ++_mali_osk_errcode_t _mali_ukk_profiling_add_event(_mali_uk_profiling_add_event_s *args) ++{ ++ /* Always add process and thread identificator in the first two data elements for events from user space */ ++ _mali_osk_profiling_add_event(args->event_id, _mali_osk_get_pid(), _mali_osk_get_tid(), args->data[2], args->data[3], args->data[4]); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_ukk_profiling_stop(_mali_uk_profiling_stop_s *args) ++{ ++ return _mali_osk_profiling_stop(&args->count); ++} ++ ++_mali_osk_errcode_t _mali_ukk_profiling_get_event(_mali_uk_profiling_get_event_s *args) ++{ ++ return _mali_osk_profiling_get_event(args->index, &args->timestamp, &args->event_id, args->data); ++} ++ ++_mali_osk_errcode_t _mali_ukk_profiling_clear(_mali_uk_profiling_clear_s *args) ++{ ++ return _mali_osk_profiling_clear(); ++} ++ ++_mali_osk_errcode_t _mali_ukk_sw_counters_report(_mali_uk_sw_counters_report_s *args) ++{ ++ _mali_osk_profiling_report_sw_counters(args->counters); ++ return _MALI_OSK_ERR_OK; ++} ++ ++/** ++ * Called by gator.ko to set HW counters ++ * ++ * @param counter_id The counter ID. ++ * @param event_id Event ID that the counter should count (HW counter value from TRM). ++ * ++ * @return 1 on success, 0 on failure. ++ */ ++int _mali_profiling_set_event(u32 counter_id, s32 event_id) ++{ ++ if (COUNTER_VP_0_C0 == counter_id) { ++ mali_gp_job_set_gp_counter_src0(event_id); ++ } else if (COUNTER_VP_0_C1 == counter_id) { ++ mali_gp_job_set_gp_counter_src1(event_id); ++ } else if (COUNTER_FP_0_C0 <= counter_id && COUNTER_FP_7_C1 >= counter_id) { ++ /* ++ * Two compatibility notes for this function: ++ * ++ * 1) Previously the DDK allowed per core counters. ++ * ++ * This did not make much sense on Mali-450 with the "virtual PP core" concept, ++ * so this option was removed, and only the same pair of HW counters was allowed on all cores, ++ * beginning with r3p2 release. ++ * ++ * Starting with r4p0, it is now possible to set different HW counters for the different sub jobs. ++ * This should be almost the same, since sub job 0 is designed to run on core 0, ++ * sub job 1 on core 1, and so on. ++ * ++ * The scheduling of PP sub jobs is not predictable, and this often led to situations where core 0 ran 2 ++ * sub jobs, while for instance core 1 ran zero. Having the counters set per sub job would thus increase ++ * the predictability of the returned data (as you would be guaranteed data for all the selected HW counters). ++ * ++ * PS: Core scaling needs to be disabled in order to use this reliably (goes for both solutions). ++ * ++ * The framework/#defines with Gator still indicates that the counter is for a particular core, ++ * but this is internally used as a sub job ID instead (no translation needed). ++ * ++ * 2) Global/default vs per sub job counters ++ * ++ * Releases before r3p2 had only per PP core counters. ++ * r3p2 releases had only one set of default/global counters which applied to all PP cores ++ * Starting with r4p0, we have both a set of default/global counters, ++ * and individual counters per sub job (equal to per core). ++ * ++ * To keep compatibility with Gator/DS-5/streamline, the following scheme is used: ++ * ++ * r3p2 release; only counters set for core 0 is handled, ++ * this is applied as the default/global set of counters, and will thus affect all cores. ++ * ++ * r4p0 release; counters set for core 0 is applied as both the global/default set of counters, ++ * and counters for sub job 0. ++ * Counters set for core 1-7 is only applied for the corresponding sub job. ++ * ++ * This should allow the DS-5/Streamline GUI to have a simple mode where it only allows setting the ++ * values for core 0, and thus this will be applied to all PP sub jobs/cores. ++ * Advanced mode will also be supported, where individual pairs of HW counters can be selected. ++ * ++ * The GUI will (until it is updated) still refer to cores instead of sub jobs, but this is probably ++ * something we can live with! ++ * ++ * Mali-450 note: Each job is not divided into a deterministic number of sub jobs, as the HW DLBU ++ * automatically distributes the load between whatever number of cores is available at this particular time. ++ * A normal PP job on Mali-450 is thus considered a single (virtual) job, and it will thus only be possible ++ * to use a single pair of HW counters (even if the job ran on multiple PP cores). ++ * In other words, only the global/default pair of PP HW counters will be used for normal Mali-450 jobs. ++ */ ++ u32 sub_job = (counter_id - COUNTER_FP_0_C0) >> 1; ++ u32 counter_src = (counter_id - COUNTER_FP_0_C0) & 1; ++ if (0 == counter_src) { ++ mali_pp_job_set_pp_counter_sub_job_src0(sub_job, event_id); ++ if (0 == sub_job) { ++ mali_pp_job_set_pp_counter_global_src0(event_id); ++ } ++ } else { ++ mali_pp_job_set_pp_counter_sub_job_src1(sub_job, event_id); ++ if (0 == sub_job) { ++ mali_pp_job_set_pp_counter_global_src1(event_id); ++ } ++ } ++ } else if (COUNTER_L2_0_C0 <= counter_id && COUNTER_L2_2_C1 >= counter_id) { ++ u32 core_id = (counter_id - COUNTER_L2_0_C0) >> 1; ++ struct mali_l2_cache_core* l2_cache_core = mali_l2_cache_core_get_glob_l2_core(core_id); ++ ++ if (NULL != l2_cache_core) { ++ u32 counter_src = (counter_id - COUNTER_L2_0_C0) & 1; ++ if (0 == counter_src) { ++ mali_l2_cache_core_set_counter_src0(l2_cache_core, event_id); ++ } else { ++ mali_l2_cache_core_set_counter_src1(l2_cache_core, event_id); ++ } ++ } ++ } else { ++ return 0; /* Failure, unknown event */ ++ } ++ ++ return 1; /* success */ ++} ++ ++/** ++ * Called by gator.ko to retrieve the L2 cache counter values for all L2 cache cores. ++ * The L2 cache counters are unique in that they are polled by gator, rather than being ++ * transmitted via the tracepoint mechanism. ++ * ++ * @param values Pointer to a _mali_profiling_l2_counter_values structure where ++ * the counter sources and values will be output ++ * @return 0 if all went well; otherwise, return the mask with the bits set for the powered off cores ++ */ ++u32 _mali_profiling_get_l2_counters(_mali_profiling_l2_counter_values *values) ++{ ++ struct mali_l2_cache_core *l2_cache; ++ u32 l2_cores_num = mali_l2_cache_core_get_glob_num_l2_cores(); ++ u32 i; ++ u32 ret = 0; ++ ++ MALI_DEBUG_ASSERT(l2_cores_num <= 3); ++ ++ for (i = 0; i < l2_cores_num; i++) { ++ l2_cache = mali_l2_cache_core_get_glob_l2_core(i); ++ ++ if (NULL == l2_cache) { ++ continue; ++ } ++ ++ if (MALI_TRUE == mali_l2_cache_lock_power_state(l2_cache)) { ++ /* It is now safe to access the L2 cache core in order to retrieve the counters */ ++ mali_l2_cache_core_get_counter_values(l2_cache, ++ &values->cores[i].source0, ++ &values->cores[i].value0, ++ &values->cores[i].source1, ++ &values->cores[i].value1); ++ } else { ++ /* The core was not available, set the right bit in the mask. */ ++ ret |= (1 << i); ++ } ++ mali_l2_cache_unlock_power_state(l2_cache); ++ } ++ ++ return ret; ++} ++ ++/** ++ * Called by gator to control the production of profiling information at runtime. ++ */ ++void _mali_profiling_control(u32 action, u32 value) ++{ ++ switch(action) { ++ case FBDUMP_CONTROL_ENABLE: ++ mali_set_user_setting(_MALI_UK_USER_SETTING_COLORBUFFER_CAPTURE_ENABLED, (value == 0 ? MALI_FALSE : MALI_TRUE)); ++ break; ++ case FBDUMP_CONTROL_RATE: ++ mali_set_user_setting(_MALI_UK_USER_SETTING_BUFFER_CAPTURE_N_FRAMES, value); ++ break; ++ case SW_COUNTER_ENABLE: ++ mali_set_user_setting(_MALI_UK_USER_SETTING_SW_COUNTER_ENABLED, value); ++ break; ++ case FBDUMP_CONTROL_RESIZE_FACTOR: ++ mali_set_user_setting(_MALI_UK_USER_SETTING_BUFFER_CAPTURE_RESIZE_FACTOR, value); ++ break; ++ default: ++ break; /* Ignore unimplemented actions */ ++ } ++} ++ ++/** ++ * Called by gator to get mali api version. ++ */ ++u32 _mali_profiling_get_api_version(void) ++{ ++ return MALI_PROFILING_API_VERSION; ++} ++ ++/** ++* Called by gator to get the data about Mali instance in use: ++* product id, version, number of cores ++*/ ++void _mali_profiling_get_mali_version(struct _mali_profiling_mali_version *values) ++{ ++ values->mali_product_id = (u32)mali_kernel_core_get_product_id(); ++ values->mali_version_major = mali_kernel_core_get_gpu_major_version(); ++ values->mali_version_minor = mali_kernel_core_get_gpu_minor_version(); ++ values->num_of_l2_cores = mali_l2_cache_core_get_glob_num_l2_cores(); ++ values->num_of_fp_cores = mali_pp_scheduler_get_num_cores_total(); ++ values->num_of_vp_cores = 1; ++} ++ ++EXPORT_SYMBOL(_mali_profiling_set_event); ++EXPORT_SYMBOL(_mali_profiling_get_l2_counters); ++EXPORT_SYMBOL(_mali_profiling_control); ++EXPORT_SYMBOL(_mali_profiling_get_api_version); ++EXPORT_SYMBOL(_mali_profiling_get_mali_version); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_specific.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_specific.h +new file mode 100644 +index 0000000..eca873f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_specific.h +@@ -0,0 +1,92 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_specific.h ++ * Defines per-OS Kernel level specifics, such as unusual workarounds for ++ * certain OSs. ++ */ ++ ++#ifndef __MALI_OSK_SPECIFIC_H__ ++#define __MALI_OSK_SPECIFIC_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "mali_osk_types.h" ++#include "mali_kernel_linux.h" ++ ++#define MALI_STATIC_INLINE static inline ++#define MALI_NON_STATIC_INLINE inline ++ ++typedef struct dma_pool * mali_dma_pool; ++ ++ ++MALI_STATIC_INLINE mali_dma_pool mali_dma_pool_create(u32 size, u32 alignment, u32 boundary) ++{ ++ return dma_pool_create("mali-dma", &mali_platform_device->dev, size, alignment, boundary); ++} ++ ++MALI_STATIC_INLINE void mali_dma_pool_destroy(mali_dma_pool pool) ++{ ++ dma_pool_destroy(pool); ++} ++ ++MALI_STATIC_INLINE mali_io_address mali_dma_pool_alloc(mali_dma_pool pool, u32 *phys_addr) ++{ ++ return dma_pool_alloc(pool, GFP_KERNEL, phys_addr); ++} ++ ++MALI_STATIC_INLINE void mali_dma_pool_free(mali_dma_pool pool, void* virt_addr, u32 phys_addr) ++{ ++ dma_pool_free(pool, virt_addr, phys_addr); ++} ++ ++ ++#if MALI_ENABLE_CPU_CYCLES ++/* Reads out the clock cycle performance counter of the current cpu. ++ It is useful for cost-free (2 cycle) measuring of the time spent ++ in a code path. Sample before and after, the diff number of cycles. ++ When the CPU is idle it will not increase this clock counter. ++ It means that the counter is accurate if only spin-locks are used, ++ but mutexes may lead to too low values since the cpu might "idle" ++ waiting for the mutex to become available. ++ The clock source is configured on the CPU during mali module load, ++ but will not give useful output after a CPU has been power cycled. ++ It is therefore important to configure the system to not turn of ++ the cpu cores when using this functionallity.*/ ++static inline unsigned int mali_get_cpu_cyclecount(void) ++{ ++ unsigned int value; ++ /* Reading the CCNT Register - CPU clock counter */ ++ asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value)); ++ return value; ++} ++ ++void mali_init_cpu_time_counters(int reset, int enable_divide_by_64); ++#endif ++ ++ ++MALI_STATIC_INLINE u32 _mali_osk_copy_from_user(void *to, void *from, u32 n) ++{ ++ return (u32)copy_from_user(to, from, (unsigned long)n); ++} ++ ++MALI_STATIC_INLINE mali_bool _mali_osk_in_atomic(void) ++{ ++ return in_atomic(); ++} ++ ++#define _mali_osk_put_user(x, ptr) put_user(x, ptr) ++ ++#endif /* __MALI_OSK_SPECIFIC_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_time.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_time.c +new file mode 100644 +index 0000000..2f1160c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_time.c +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_time.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include "mali_osk.h" ++#include ++#include ++#include ++ ++int _mali_osk_time_after( u32 ticka, u32 tickb ) ++{ ++ return time_after((unsigned long)ticka, (unsigned long)tickb); ++} ++ ++u32 _mali_osk_time_mstoticks( u32 ms ) ++{ ++ return msecs_to_jiffies(ms); ++} ++ ++u32 _mali_osk_time_tickstoms( u32 ticks ) ++{ ++ return jiffies_to_msecs(ticks); ++} ++ ++u32 _mali_osk_time_tickcount( void ) ++{ ++ return jiffies; ++} ++ ++void _mali_osk_time_ubusydelay( u32 usecs ) ++{ ++ udelay(usecs); ++} ++ ++u64 _mali_osk_time_get_ns( void ) ++{ ++ struct timespec tsval; ++ getnstimeofday(&tsval); ++ return (u64)timespec_to_ns(&tsval); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_timers.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_timers.c +new file mode 100644 +index 0000000..3f179be +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_timers.c +@@ -0,0 +1,76 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_timers.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include ++#include ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++struct _mali_osk_timer_t_struct { ++ struct timer_list timer; ++}; ++ ++typedef void (*timer_timeout_function_t)(unsigned long); ++ ++_mali_osk_timer_t *_mali_osk_timer_init(void) ++{ ++ _mali_osk_timer_t *t = (_mali_osk_timer_t*)kmalloc(sizeof(_mali_osk_timer_t), GFP_KERNEL); ++ if (NULL != t) init_timer(&t->timer); ++ return t; ++} ++ ++void _mali_osk_timer_add( _mali_osk_timer_t *tim, u32 ticks_to_expire ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ tim->timer.expires = jiffies + ticks_to_expire; ++ add_timer(&(tim->timer)); ++} ++ ++void _mali_osk_timer_mod( _mali_osk_timer_t *tim, u32 ticks_to_expire) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ mod_timer(&(tim->timer), jiffies + ticks_to_expire); ++} ++ ++void _mali_osk_timer_del( _mali_osk_timer_t *tim ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ del_timer_sync(&(tim->timer)); ++} ++ ++void _mali_osk_timer_del_async( _mali_osk_timer_t *tim ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ del_timer(&(tim->timer)); ++} ++ ++mali_bool _mali_osk_timer_pending( _mali_osk_timer_t *tim ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ return 1 == timer_pending(&(tim->timer)); ++} ++ ++void _mali_osk_timer_setcallback( _mali_osk_timer_t *tim, _mali_osk_timer_callback_t callback, void *data ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ tim->timer.data = (unsigned long)data; ++ tim->timer.function = (timer_timeout_function_t)callback; ++} ++ ++void _mali_osk_timer_term( _mali_osk_timer_t *tim ) ++{ ++ MALI_DEBUG_ASSERT_POINTER(tim); ++ kfree(tim); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wait_queue.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wait_queue.c +new file mode 100644 +index 0000000..ab803b1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wait_queue.c +@@ -0,0 +1,78 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_wait_queue.c ++ * Implemenation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include ++#include ++#include ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++ ++struct _mali_osk_wait_queue_t_struct { ++ wait_queue_head_t wait_queue; ++}; ++ ++_mali_osk_wait_queue_t* _mali_osk_wait_queue_init( void ) ++{ ++ _mali_osk_wait_queue_t* ret = NULL; ++ ++ ret = kmalloc(sizeof(_mali_osk_wait_queue_t), GFP_KERNEL); ++ ++ if (NULL == ret) { ++ return ret; ++ } ++ ++ init_waitqueue_head(&ret->wait_queue); ++ MALI_DEBUG_ASSERT(!waitqueue_active(&ret->wait_queue)); ++ ++ return ret; ++} ++ ++void _mali_osk_wait_queue_wait_event( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void *), void *data ) ++{ ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ MALI_DEBUG_PRINT(6, ("Adding to wait queue %p\n", queue)); ++ wait_event(queue->wait_queue, condition(data)); ++} ++ ++void _mali_osk_wait_queue_wait_event_timeout( _mali_osk_wait_queue_t *queue, mali_bool (*condition)(void *), void *data, u32 timeout ) ++{ ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ MALI_DEBUG_PRINT(6, ("Adding to wait queue %p\n", queue)); ++ wait_event_timeout(queue->wait_queue, condition(data), _mali_osk_time_mstoticks(timeout)); ++} ++ ++void _mali_osk_wait_queue_wake_up( _mali_osk_wait_queue_t *queue ) ++{ ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ ++ /* if queue is empty, don't attempt to wake up its elements */ ++ if (!waitqueue_active(&queue->wait_queue)) return; ++ ++ MALI_DEBUG_PRINT(6, ("Waking up elements in wait queue %p ....\n", queue)); ++ ++ wake_up_all(&queue->wait_queue); ++ ++ MALI_DEBUG_PRINT(6, ("... elements in wait queue %p woken up\n", queue)); ++} ++ ++void _mali_osk_wait_queue_term( _mali_osk_wait_queue_t *queue ) ++{ ++ /* Parameter validation */ ++ MALI_DEBUG_ASSERT_POINTER( queue ); ++ ++ /* Linux requires no explicit termination of wait queues */ ++ kfree(queue); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wq.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wq.c +new file mode 100644 +index 0000000..d07977a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_osk_wq.c +@@ -0,0 +1,231 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_osk_wq.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++#include /* For memory allocation */ ++#include ++#include ++#include ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_kernel_license.h" ++#include "mali_kernel_linux.h" ++ ++typedef struct _mali_osk_wq_work_s { ++ _mali_osk_wq_work_handler_t handler; ++ void *data; ++ mali_bool high_pri; ++ struct work_struct work_handle; ++} mali_osk_wq_work_object_t; ++ ++typedef struct _mali_osk_wq_delayed_work_s { ++ _mali_osk_wq_work_handler_t handler; ++ void *data; ++ struct delayed_work work; ++} mali_osk_wq_delayed_work_object_t; ++ ++#if MALI_LICENSE_IS_GPL ++struct workqueue_struct *mali_wq_normal = NULL; ++struct workqueue_struct *mali_wq_high = NULL; ++#endif ++ ++static void _mali_osk_wq_work_func(struct work_struct *work); ++ ++_mali_osk_errcode_t _mali_osk_wq_init(void) ++{ ++#if MALI_LICENSE_IS_GPL ++ MALI_DEBUG_ASSERT(NULL == mali_wq_normal); ++ MALI_DEBUG_ASSERT(NULL == mali_wq_high); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) ++ mali_wq_normal = alloc_workqueue("mali", WQ_UNBOUND, 0); ++ mali_wq_high = alloc_workqueue("mali_high_pri", WQ_HIGHPRI, 0); ++#else ++ mali_wq_normal = create_workqueue("mali"); ++ mali_wq_high = create_workqueue("mali_high_pri"); ++#endif ++ if (NULL == mali_wq_normal || NULL == mali_wq_high) { ++ MALI_PRINT_ERROR(("Unable to create Mali workqueues\n")); ++ ++ if (mali_wq_normal) destroy_workqueue(mali_wq_normal); ++ if (mali_wq_high) destroy_workqueue(mali_wq_high); ++ ++ mali_wq_normal = NULL; ++ mali_wq_high = NULL; ++ ++ return _MALI_OSK_ERR_FAULT; ++ } ++#endif /* MALI_LICENSE_IS_GPL */ ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _mali_osk_wq_flush(void) ++{ ++#if MALI_LICENSE_IS_GPL ++ flush_workqueue(mali_wq_high); ++ flush_workqueue(mali_wq_normal); ++#else ++ flush_scheduled_work(); ++#endif ++} ++ ++void _mali_osk_wq_term(void) ++{ ++#if MALI_LICENSE_IS_GPL ++ MALI_DEBUG_ASSERT(NULL != mali_wq_normal); ++ MALI_DEBUG_ASSERT(NULL != mali_wq_high); ++ ++ flush_workqueue(mali_wq_normal); ++ destroy_workqueue(mali_wq_normal); ++ ++ flush_workqueue(mali_wq_high); ++ destroy_workqueue(mali_wq_high); ++ ++ mali_wq_normal = NULL; ++ mali_wq_high = NULL; ++#else ++ flush_scheduled_work(); ++#endif ++} ++ ++_mali_osk_wq_work_t *_mali_osk_wq_create_work( _mali_osk_wq_work_handler_t handler, void *data ) ++{ ++ mali_osk_wq_work_object_t *work = kmalloc(sizeof(mali_osk_wq_work_object_t), GFP_KERNEL); ++ ++ if (NULL == work) return NULL; ++ ++ work->handler = handler; ++ work->data = data; ++ work->high_pri = MALI_FALSE; ++ ++ INIT_WORK( &work->work_handle, _mali_osk_wq_work_func); ++ ++ return work; ++} ++ ++_mali_osk_wq_work_t *_mali_osk_wq_create_work_high_pri( _mali_osk_wq_work_handler_t handler, void *data ) ++{ ++ mali_osk_wq_work_object_t *work = kmalloc(sizeof(mali_osk_wq_work_object_t), GFP_KERNEL); ++ ++ if (NULL == work) return NULL; ++ ++ work->handler = handler; ++ work->data = data; ++ work->high_pri = MALI_TRUE; ++ ++ INIT_WORK( &work->work_handle, _mali_osk_wq_work_func ); ++ ++ return work; ++} ++ ++void _mali_osk_wq_delete_work( _mali_osk_wq_work_t *work ) ++{ ++ mali_osk_wq_work_object_t *work_object = (mali_osk_wq_work_object_t *)work; ++ _mali_osk_wq_flush(); ++ kfree(work_object); ++} ++ ++void _mali_osk_wq_delete_work_nonflush( _mali_osk_wq_work_t *work ) ++{ ++ mali_osk_wq_work_object_t *work_object = (mali_osk_wq_work_object_t *)work; ++ kfree(work_object); ++} ++ ++void _mali_osk_wq_schedule_work( _mali_osk_wq_work_t *work ) ++{ ++ mali_osk_wq_work_object_t *work_object = (mali_osk_wq_work_object_t *)work; ++#if MALI_LICENSE_IS_GPL ++ queue_work(mali_wq_normal, &work_object->work_handle); ++#else ++ schedule_work(&work_object->work_handle); ++#endif ++} ++ ++void _mali_osk_wq_schedule_work_high_pri( _mali_osk_wq_work_t *work ) ++{ ++ mali_osk_wq_work_object_t *work_object = (mali_osk_wq_work_object_t *)work; ++#if MALI_LICENSE_IS_GPL ++ queue_work(mali_wq_high, &work_object->work_handle); ++#else ++ schedule_work(&work_object->work_handle); ++#endif ++} ++ ++static void _mali_osk_wq_work_func( struct work_struct *work ) ++{ ++ mali_osk_wq_work_object_t *work_object; ++ ++ work_object = _MALI_OSK_CONTAINER_OF(work, mali_osk_wq_work_object_t, work_handle); ++ ++ /* We want higher priority than the Dynamic Priority, setting it to the lowest of the RT priorities */ ++ if (MALI_TRUE == work_object->high_pri) { ++ set_user_nice(current, -19); ++ } ++ ++ work_object->handler(work_object->data); ++} ++ ++static void _mali_osk_wq_delayed_work_func( struct work_struct *work ) ++{ ++ mali_osk_wq_delayed_work_object_t *work_object; ++ ++ work_object = _MALI_OSK_CONTAINER_OF(work, mali_osk_wq_delayed_work_object_t, work.work); ++ work_object->handler(work_object->data); ++} ++ ++mali_osk_wq_delayed_work_object_t *_mali_osk_wq_delayed_create_work( _mali_osk_wq_work_handler_t handler, void *data) ++{ ++ mali_osk_wq_delayed_work_object_t *work = kmalloc(sizeof(mali_osk_wq_delayed_work_object_t), GFP_KERNEL); ++ ++ if (NULL == work) return NULL; ++ ++ work->handler = handler; ++ work->data = data; ++ ++ INIT_DELAYED_WORK(&work->work, _mali_osk_wq_delayed_work_func); ++ ++ return work; ++} ++ ++void _mali_osk_wq_delayed_delete_work_nonflush( _mali_osk_wq_delayed_work_t *work ) ++{ ++ mali_osk_wq_delayed_work_object_t *work_object = (mali_osk_wq_delayed_work_object_t *)work; ++ kfree(work_object); ++} ++ ++void _mali_osk_wq_delayed_cancel_work_async( _mali_osk_wq_delayed_work_t *work ) ++{ ++ mali_osk_wq_delayed_work_object_t *work_object = (mali_osk_wq_delayed_work_object_t *)work; ++ cancel_delayed_work(&work_object->work); ++} ++ ++void _mali_osk_wq_delayed_cancel_work_sync( _mali_osk_wq_delayed_work_t *work ) ++{ ++ mali_osk_wq_delayed_work_object_t *work_object = (mali_osk_wq_delayed_work_object_t *)work; ++ cancel_delayed_work_sync(&work_object->work); ++} ++ ++void _mali_osk_wq_delayed_schedule_work( _mali_osk_wq_delayed_work_t *work, u32 delay ) ++{ ++ mali_osk_wq_delayed_work_object_t *work_object = (mali_osk_wq_delayed_work_object_t *)work; ++ ++#if MALI_LICENSE_IS_GPL ++ queue_delayed_work(mali_wq_normal, &work_object->work, delay); ++#else ++ schedule_delayed_work(&work_object->work, delay); ++#endif ++ ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_platform.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_platform.c +new file mode 100644 +index 0000000..1515985 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_platform.c +@@ -0,0 +1,590 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if defined(CONFIG_CPU_BUDGET_THERMAL) ++#include ++static int cur_mode = 0; ++#elif defined(CONFIG_SW_POWERNOW) ++#include ++#endif ++#ifdef CONFIG_HAS_EARLYSUSPEND ++#include ++#endif /* CONFIG_HAS_EARLYSUSPEND */ ++ ++#include "mali_kernel_linux.h" ++ ++static struct clk *mali_clk = NULL; ++static struct clk *gpu_pll = NULL; ++extern unsigned long totalram_pages; ++ ++struct __fb_addr_para ++{ ++ unsigned int fb_paddr; ++ unsigned int fb_size; ++}; ++ ++extern void sunxi_get_fb_addr_para(struct __fb_addr_para *fb_addr_para); ++#ifdef CONFIG_HAS_EARLYSUSPEND ++static void mali_driver_early_suspend_scheduler(struct early_suspend *h); ++static void mali_driver_late_resume_scheduler(struct early_suspend *h); ++#endif /* CONFIG_HAS_EARLYSUSPEND */ ++ ++extern int ths_read_data(int value); ++ ++static unsigned int freq_table[4] = ++{ ++ 128, /* for early suspend */ ++ 252, /* for play video mode */ ++#if !defined(CONFIG_ARCH_SUN8IW7P1) ++ 384, /* for normal mode */ ++ 384, /* for extreme mode */ ++#elif defined(CONFIG_ARCH_SUN8IW7P1) ++ 576, /* for normal mode */ ++ 576, /* for extreme mode */ ++#endif ++}; ++ ++#if defined(CONFIG_ARCH_SUN8IW7P1) ++static unsigned int thermal_ctrl_freq[] = {576, 432, 312, 120}; ++ ++/* This data is for sensor, but the data of gpu may be 5 degress Centigrade higher */ ++static unsigned int temperature_threshold[] = {70, 80, 90}; /* degress Centigrade */ ++#endif /* defined(CONFIG_ARCH_SUN8IW7P1) */ ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++static struct early_suspend mali_early_suspend_handler = ++{ ++ .level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 100, ++ .suspend = mali_driver_early_suspend_scheduler, ++ .resume = mali_driver_late_resume_scheduler, ++}; ++#endif /* CONFIG_HAS_EARLYSUSPEND */ ++ ++static struct mali_gpu_device_data mali_gpu_data; ++ ++#if defined(CONFIG_ARCH_SUN8IW3P1) || defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW9P1) ++static struct resource mali_gpu_resources[]= ++{ ++ MALI_GPU_RESOURCES_MALI400_MP2_PMU(SUNXI_GPU_PBASE, SUNXI_IRQ_GPUGP, SUNXI_IRQ_GPUGPMMU, \ ++ SUNXI_IRQ_GPUPP0, SUNXI_IRQ_GPUPPMMU0, SUNXI_IRQ_GPUPP1, SUNXI_IRQ_GPUPPMMU1) ++}; ++#elif defined(CONFIG_ARCH_SUN8IW7P1) ++static struct resource mali_gpu_resources[]= ++{ ++ MALI_GPU_RESOURCES_MALI400_MP2_PMU(SUNXI_GPU_PBASE, SUNXI_IRQ_GPU_GP, SUNXI_IRQ_GPU_GPMMU, \ ++ SUNXI_IRQ_GPU_PP0, SUNXI_IRQ_GPU_PPMMU0, SUNXI_IRQ_GPU_PP1, SUNXI_IRQ_GPU_PPMMU1) ++}; ++#endif ++ ++static struct platform_device mali_gpu_device = ++{ ++ .name = MALI_GPU_NAME_UTGARD, ++ .id = 0, ++ .dev.coherent_dma_mask = DMA_BIT_MASK(32), ++}; ++ ++/* ++ ++*************************************************************** ++ @Function :get_gpu_clk ++ ++ @Description:Get gpu related clocks ++ ++ @Input :None ++ ++ @Return :Zero or error code ++*************************************************************** ++*/ ++static int get_gpu_clk(void) ++{ ++#if defined(CONFIG_ARCH_SUN8IW3P1) ++ gpu_pll = clk_get(NULL, PLL8_CLK); ++#elif defined(CONFIG_ARCH_SUN8IW5P1) || defined(CONFIG_ARCH_SUN8IW7P1) || defined(CONFIG_ARCH_SUN8IW9P1) ++ gpu_pll = clk_get(NULL, PLL_GPU_CLK); ++#endif ++ if(!gpu_pll || IS_ERR(gpu_pll)) ++ { ++ printk(KERN_ERR "Failed to get gpu pll clock!\n"); ++ return -1; ++ } ++ ++ mali_clk = clk_get(NULL, GPU_CLK); ++ if(!mali_clk || IS_ERR(mali_clk)) ++ { ++ printk(KERN_ERR "Failed to get mali clock!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/* ++*************************************************************** ++ @Function :set_freq ++ ++ @Description:Set the frequency of gpu related clocks ++ ++ @Input :Frequency value ++ ++ @Return :Zero or error code ++*************************************************************** ++*/ ++static int set_freq(int freq /* MHz */) ++{ ++ if(clk_set_rate(gpu_pll, freq*1000*1000)) ++ { ++ printk(KERN_ERR "Failed to set gpu pll clock!\n"); ++ return -1; ++ } ++ ++ if(clk_set_rate(mali_clk, freq*1000*1000)) ++ { ++ printk(KERN_ERR "Failed to set mali clock!\n"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#if defined(CONFIG_CPU_BUDGET_THERMAL) || defined(CONFIG_SW_POWERNOW) || defined(CONFIG_HAS_EARLYSUSPEND) ++/* ++*************************************************************** ++ @Function :mali_set_freq ++ ++ @Description:Set the frequency of gpu related clocks with mali dvfs function ++ ++ @Input :Frequency value ++ ++ @Return :Zero or error code ++*************************************************************** ++*/ ++static int mali_set_freq(int freq /* MHz */) ++{ ++ int err; ++ mali_dev_pause(); ++ err = set_freq(freq); ++ mali_dev_resume(); ++ return err; ++} ++#endif /* defined(CONFIG_CPU_BUDGET_THERMAL) || defined(CONFIG_SW_POWERNOW) || defined(CONFIG_HAS_EARLYSUSPEND) */ ++ ++/* ++*************************************************************** ++ @Function :enable_gpu_clk ++ ++ @Description:Enable gpu related clocks ++ ++ @Input :None ++ ++ @Return :None ++*************************************************************** ++*/ ++void enable_gpu_clk(void) ++{ ++ if(mali_clk->enable_count == 0) ++ { ++ if(clk_prepare_enable(gpu_pll)) ++ { ++ printk(KERN_ERR "Failed to enable gpu pll!\n"); ++ } ++ ++ if(clk_prepare_enable(mali_clk)) ++ { ++ printk(KERN_ERR "Failed to enable mali clock!\n"); ++ } ++ } ++} ++ ++/* ++*************************************************************** ++ @Function :disable_gpu_clk ++ ++ @Description:Disable gpu related clocks ++ ++ @Input :None ++ ++ @Return :None ++*************************************************************** ++*/ ++void disable_gpu_clk(void) ++{ ++ if(mali_clk->enable_count == 1) ++ { ++ clk_disable_unprepare(mali_clk); ++ clk_disable_unprepare(gpu_pll); ++ } ++} ++ ++#if defined(CONFIG_CPU_BUDGET_THERMAL) ++/* ++*************************************************************** ++ @Function :mali_throttle_notifier_call ++ ++ @Description:The callback function of throttle notifier ++ ++ @Input :nfb, mode, cmd ++ ++ @Return :retval ++*************************************************************** ++*/ ++static int mali_throttle_notifier_call(struct notifier_block *nfb, unsigned long mode, void *cmd) ++{ ++ int retval = NOTIFY_DONE; ++ ++#if !defined(CONFIG_ARCH_SUN8IW7P1) ++ if(mode == BUDGET_GPU_THROTTLE && cur_mode == 1) ++ { ++ mali_set_freq(freq_table[2]); ++ cur_mode = 0; ++ } ++ else ++ { ++ if(cmd && (*(int *)cmd) == 1 && cur_mode != 1) ++ { ++ mali_set_freq(freq_table[3]); ++ cur_mode = 1; ++ } ++ else if(cmd && (*(int *)cmd) == 0 && cur_mode != 0) ++ { ++ mali_set_freq(freq_table[2]); ++ cur_mode = 0; ++ } ++ else if(cmd && (*(int *)cmd) == 2 && cur_mode != 2) ++ { ++ mali_set_freq(freq_table[1]); ++ cur_mode = 2; ++ } ++ } ++#elif defined(CONFIG_ARCH_SUN8IW7P1) ++ int temperature = 0; ++ int i = 0; ++ temperature = ths_read_data(4); ++ for(i=0;i 0) ++ { ++ freq_table[2] = mali_clk_freq.val; ++ } ++ } ++ else ++ { ++ goto err_out; ++ } ++ ++ if(SCIRPT_ITEM_VALUE_TYPE_INT == script_get_item("mali_para", "mali_used", &mali_used)) ++ { ++ if(mali_used.val == 1) ++ { ++ if(SCIRPT_ITEM_VALUE_TYPE_INT == script_get_item("mali_para", "mali_extreme_freq", &mali_max_freq)) ++ { ++ if (mali_max_freq.val >= mali_clk_freq.val) ++ { ++ freq_table[3] = mali_max_freq.val; ++ } ++ else ++ { ++ freq_table[3] = mali_clk_freq.val; ++ } ++ } ++ else ++ { ++ goto err_out; ++ } ++ } ++ } ++ else ++ { ++ goto err_out; ++ } ++ ++ printk(KERN_INFO "Get mali parameter successfully\n"); ++ return; ++ ++err_out: ++ printk(KERN_ERR "Failed to get mali parameter!\n"); ++ return; ++} ++ ++/* ++*************************************************************** ++ @Function :mali_platform_init ++ ++ @Description:Init the power and clocks of gpu ++ ++ @Input :None ++ ++ @Return :Zero or error code ++*************************************************************** ++*/ ++static int mali_platform_init(void) ++{ ++ parse_fex(); ++ ++ if(get_gpu_clk()) ++ { ++ goto err_out; ++ } ++ ++ if(set_freq(freq_table[2])) ++ { ++ goto err_out; ++ } ++ ++ enable_gpu_clk(); ++ ++#if defined(CONFIG_CPU_BUDGET_THERMAL) ++ register_budget_cooling_notifier(&mali_throttle_notifier); ++#elif defined(CONFIG_SW_POWERNOW) ++ register_sw_powernow_notifier(&mali_powernow_notifier); ++#endif ++#ifdef CONFIG_HAS_EARLYSUSPEND ++ register_early_suspend(&mali_early_suspend_handler); ++#endif /* CONFIG_HAS_EARLYSUSPEND */ ++ ++ printk(KERN_INFO "Init Mali gpu successfully\n"); ++ return 0; ++ ++err_out: ++ printk(KERN_ERR "Failed to init Mali gpu!\n"); ++ return -1; ++} ++ ++/* ++*************************************************************** ++ @Function :mali_platform_device_unregister ++ ++ @Description:Unregister mali platform device ++ ++ @Input :None ++ ++ @Return :Zero ++*************************************************************** ++*/ ++static int mali_platform_device_unregister(void) ++{ ++ platform_device_unregister(&mali_gpu_device); ++ ++#if defined(CONFIG_SW_POWERNOW) ++ unregister_sw_powernow_notifier(&mali_powernow_notifier); ++#endif /* CONFIG_SW_POWERNOW */ ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++ unregister_early_suspend(&mali_early_suspend_handler); ++#endif /* CONFIG_HAS_EARLYSUSPEND */ ++ ++ disable_gpu_clk(); ++ ++ return 0; ++} ++ ++/* ++*************************************************************** ++ @Function :sun8i_mali_platform_device_register ++ ++ @Description:Register mali platform device ++ ++ @Input :None ++ ++ @Return :Zero or error code ++*************************************************************** ++*/ ++int sun8i_mali_platform_device_register(void) ++{ ++ int err; ++ struct __fb_addr_para fb_addr_para = {0}; ++ ++ sunxi_get_fb_addr_para(&fb_addr_para); ++ ++ err = platform_device_add_resources(&mali_gpu_device, mali_gpu_resources, sizeof(mali_gpu_resources) / sizeof(mali_gpu_resources[0])); ++ if (0 == err) ++ { ++ mali_gpu_data.fb_start = fb_addr_para.fb_paddr; ++ mali_gpu_data.fb_size = fb_addr_para.fb_size; ++ mali_gpu_data.shared_mem_size = totalram_pages * PAGE_SIZE; /* B */ ++ ++ err = platform_device_add_data(&mali_gpu_device, &mali_gpu_data, sizeof(mali_gpu_data)); ++ if(0 == err) ++ { ++ err = platform_device_register(&mali_gpu_device); ++ ++ if (0 == err) ++ { ++ if(0 != mali_platform_init()) ++ { ++ return -1; ++ } ++#if defined(CONFIG_PM_RUNTIME) ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pm_runtime_set_autosuspend_delay(&(mali_gpu_device.dev), 1000); ++ pm_runtime_use_autosuspend(&(mali_gpu_device.dev)); ++#endif ++ pm_runtime_enable(&(mali_gpu_device.dev)); ++#endif /* CONFIG_PM_RUNTIME */ ++ ++ return 0; ++ } ++ } ++ ++ mali_platform_device_unregister(); ++ } ++ ++ return err; ++} ++ ++#ifdef CONFIG_HAS_EARLYSUSPEND ++/* ++*************************************************************** ++ @Function :mali_driver_early_suspend_scheduler ++ ++ @Description:The callback function of early suspend ++ ++ @Input :h ++ ++ @Return :None ++*************************************************************** ++*/ ++static void mali_driver_early_suspend_scheduler(struct early_suspend *h) ++{ ++ mali_set_freq(freq_table[0]); ++} ++ ++/* ++*************************************************************** ++ @Function :mali_driver_late_resume_scheduler ++ ++ @Description:The callback function of early suspend ++ ++ @Input :h ++ ++ @Return :None ++*************************************************************** ++*/ ++static void mali_driver_late_resume_scheduler(struct early_suspend *h) ++{ ++ mali_set_freq(freq_table[2]); ++} ++#endif /* CONFIG_HAS_EARLYSUSPEND */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_pmu_power_up_down.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_pmu_power_up_down.c +new file mode 100644 +index 0000000..0c313a3 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_pmu_power_up_down.c +@@ -0,0 +1,71 @@ ++/** ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_pmu_power_up_down.c ++ */ ++ ++#include ++#include ++#include ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_pmu.h" ++#include "mali_pp_scheduler.h" ++#include "linux/mali/mali_utgard.h" ++ ++/* Mali PMU power up/down APIs */ ++ ++int mali_pmu_powerup(void) ++{ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ ++ MALI_DEBUG_PRINT(5, ("Mali PMU: Power up\n")); ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ if (NULL == pmu) { ++ return -ENXIO; ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_pmu_power_up_all(pmu)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(mali_pmu_powerup); ++ ++int mali_pmu_powerdown(void) ++{ ++ struct mali_pmu_core *pmu = mali_pmu_get_global_pmu_core(); ++ ++ MALI_DEBUG_PRINT(5, ("Mali PMU: Power down\n")); ++ ++ MALI_DEBUG_ASSERT_POINTER(pmu); ++ if (NULL == pmu) { ++ return -ENXIO; ++ } ++ ++ if (_MALI_OSK_ERR_OK != mali_pmu_power_down_all(pmu)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++EXPORT_SYMBOL(mali_pmu_powerdown); ++ ++int mali_perf_set_num_pp_cores(unsigned int num_cores) ++{ ++ return mali_pp_scheduler_set_perf_level(num_cores, MALI_FALSE); ++} ++ ++EXPORT_SYMBOL(mali_perf_set_num_pp_cores); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_events.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_events.h +new file mode 100644 +index 0000000..2639a40 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_events.h +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2012 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PROFILING_EVENTS_H__ ++#define __MALI_PROFILING_EVENTS_H__ ++ ++/* Simple wrapper in order to find the OS specific location of this file */ ++#include ++ ++#endif /* __MALI_PROFILING_EVENTS_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_gator_api.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_gator_api.h +new file mode 100644 +index 0000000..e3d836f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_gator_api.h +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PROFILING_GATOR_API_H__ ++#define __MALI_PROFILING_GATOR_API_H__ ++ ++/* Simple wrapper in order to find the OS specific location of this file */ ++#include ++ ++#endif /* __MALI_PROFILING_GATOR_API_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.c +new file mode 100644 +index 0000000..c05028b +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.c +@@ -0,0 +1,274 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_osk_mali.h" ++#include "mali_ukk.h" ++#include "mali_timestamp.h" ++#include "mali_osk_profiling.h" ++#include "mali_user_settings_db.h" ++#include "mali_profiling_internal.h" ++ ++typedef struct mali_profiling_entry { ++ u64 timestamp; ++ u32 event_id; ++ u32 data[5]; ++} mali_profiling_entry; ++ ++typedef enum mali_profiling_state { ++ MALI_PROFILING_STATE_UNINITIALIZED, ++ MALI_PROFILING_STATE_IDLE, ++ MALI_PROFILING_STATE_RUNNING, ++ MALI_PROFILING_STATE_RETURN, ++} mali_profiling_state; ++ ++static _mali_osk_mutex_t *lock = NULL; ++static mali_profiling_state prof_state = MALI_PROFILING_STATE_UNINITIALIZED; ++static mali_profiling_entry* profile_entries = NULL; ++static _mali_osk_atomic_t profile_insert_index; ++static u32 profile_mask = 0; ++ ++static inline void add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4); ++ ++void probe_mali_timeline_event(void *data, TP_PROTO(unsigned int event_id, unsigned int d0, unsigned int d1, unsigned ++ int d2, unsigned int d3, unsigned int d4)) ++{ ++ add_event(event_id, d0, d1, d2, d3, d4); ++} ++ ++_mali_osk_errcode_t _mali_internal_profiling_init(mali_bool auto_start) ++{ ++ profile_entries = NULL; ++ profile_mask = 0; ++ _mali_osk_atomic_init(&profile_insert_index, 0); ++ ++ lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_ORDERED, _MALI_OSK_LOCK_ORDER_PROFILING); ++ if (NULL == lock) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ prof_state = MALI_PROFILING_STATE_IDLE; ++ ++ if (MALI_TRUE == auto_start) { ++ u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* Use maximum buffer size */ ++ ++ mali_set_user_setting(_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, MALI_TRUE); ++ if (_MALI_OSK_ERR_OK != _mali_internal_profiling_start(&limit)) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _mali_internal_profiling_term(void) ++{ ++ u32 count; ++ ++ /* Ensure profiling is stopped */ ++ _mali_internal_profiling_stop(&count); ++ ++ prof_state = MALI_PROFILING_STATE_UNINITIALIZED; ++ ++ if (NULL != profile_entries) { ++ _mali_osk_vfree(profile_entries); ++ profile_entries = NULL; ++ } ++ ++ if (NULL != lock) { ++ _mali_osk_mutex_term(lock); ++ lock = NULL; ++ } ++} ++ ++_mali_osk_errcode_t _mali_internal_profiling_start(u32 * limit) ++{ ++ _mali_osk_errcode_t ret; ++ mali_profiling_entry *new_profile_entries; ++ ++ _mali_osk_mutex_wait(lock); ++ ++ if (MALI_PROFILING_STATE_RUNNING == prof_state) { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_BUSY; ++ } ++ ++ new_profile_entries = _mali_osk_valloc(*limit * sizeof(mali_profiling_entry)); ++ ++ if (NULL == new_profile_entries) { ++ _mali_osk_vfree(new_profile_entries); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ if (MALI_PROFILING_MAX_BUFFER_ENTRIES < *limit) { ++ *limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; ++ } ++ ++ profile_mask = 1; ++ while (profile_mask <= *limit) { ++ profile_mask <<= 1; ++ } ++ profile_mask >>= 1; ++ ++ *limit = profile_mask; ++ ++ profile_mask--; /* turns the power of two into a mask of one less */ ++ ++ if (MALI_PROFILING_STATE_IDLE != prof_state) { ++ _mali_osk_mutex_signal(lock); ++ _mali_osk_vfree(new_profile_entries); ++ return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ ++ } ++ ++ profile_entries = new_profile_entries; ++ ++ ret = _mali_timestamp_reset(); ++ ++ if (_MALI_OSK_ERR_OK == ret) { ++ prof_state = MALI_PROFILING_STATE_RUNNING; ++ } else { ++ _mali_osk_vfree(profile_entries); ++ profile_entries = NULL; ++ } ++ ++ register_trace_mali_timeline_event(probe_mali_timeline_event, NULL); ++ ++ _mali_osk_mutex_signal(lock); ++ return ret; ++} ++ ++static inline void add_event(u32 event_id, u32 data0, u32 data1, u32 data2, u32 data3, u32 data4) ++{ ++ u32 cur_index = (_mali_osk_atomic_inc_return(&profile_insert_index) - 1) & profile_mask; ++ ++ profile_entries[cur_index].timestamp = _mali_timestamp_get(); ++ profile_entries[cur_index].event_id = event_id; ++ profile_entries[cur_index].data[0] = data0; ++ profile_entries[cur_index].data[1] = data1; ++ profile_entries[cur_index].data[2] = data2; ++ profile_entries[cur_index].data[3] = data3; ++ profile_entries[cur_index].data[4] = data4; ++ ++ /* If event is "leave API function", add current memory usage to the event ++ * as data point 4. This is used in timeline profiling to indicate how ++ * much memory was used when leaving a function. */ ++ if (event_id == (MALI_PROFILING_EVENT_TYPE_SINGLE|MALI_PROFILING_EVENT_CHANNEL_SOFTWARE|MALI_PROFILING_EVENT_REASON_SINGLE_SW_LEAVE_API_FUNC)) { ++ profile_entries[cur_index].data[4] = _mali_ukk_report_memory_usage(); ++ } ++} ++ ++_mali_osk_errcode_t _mali_internal_profiling_stop(u32 * count) ++{ ++ _mali_osk_mutex_wait(lock); ++ ++ if (MALI_PROFILING_STATE_RUNNING != prof_state) { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ ++ } ++ ++ /* go into return state (user to retreive events), no more events will be added after this */ ++ prof_state = MALI_PROFILING_STATE_RETURN; ++ ++ unregister_trace_mali_timeline_event(probe_mali_timeline_event, NULL); ++ ++ _mali_osk_mutex_signal(lock); ++ ++ tracepoint_synchronize_unregister(); ++ ++ *count = _mali_osk_atomic_read(&profile_insert_index); ++ if (*count > profile_mask) *count = profile_mask; ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++u32 _mali_internal_profiling_get_count(void) ++{ ++ u32 retval = 0; ++ ++ _mali_osk_mutex_wait(lock); ++ if (MALI_PROFILING_STATE_RETURN == prof_state) { ++ retval = _mali_osk_atomic_read(&profile_insert_index); ++ if (retval > profile_mask) retval = profile_mask; ++ } ++ _mali_osk_mutex_signal(lock); ++ ++ return retval; ++} ++ ++_mali_osk_errcode_t _mali_internal_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]) ++{ ++ u32 raw_index = _mali_osk_atomic_read(&profile_insert_index); ++ ++ _mali_osk_mutex_wait(lock); ++ ++ if (index < profile_mask) { ++ if ((raw_index & ~profile_mask) != 0) { ++ index += raw_index; ++ index &= profile_mask; ++ } ++ ++ if (prof_state != MALI_PROFILING_STATE_RETURN) { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ ++ } ++ ++ if(index >= raw_index) { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ *timestamp = profile_entries[index].timestamp; ++ *event_id = profile_entries[index].event_id; ++ data[0] = profile_entries[index].data[0]; ++ data[1] = profile_entries[index].data[1]; ++ data[2] = profile_entries[index].data[2]; ++ data[3] = profile_entries[index].data[3]; ++ data[4] = profile_entries[index].data[4]; ++ } else { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _mali_internal_profiling_clear(void) ++{ ++ _mali_osk_mutex_wait(lock); ++ ++ if (MALI_PROFILING_STATE_RETURN != prof_state) { ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_INVALID_ARGS; /* invalid to call this function in this state */ ++ } ++ ++ prof_state = MALI_PROFILING_STATE_IDLE; ++ profile_mask = 0; ++ _mali_osk_atomic_init(&profile_insert_index, 0); ++ ++ if (NULL != profile_entries) { ++ _mali_osk_vfree(profile_entries); ++ profile_entries = NULL; ++ } ++ ++ _mali_osk_mutex_signal(lock); ++ return _MALI_OSK_ERR_OK; ++} ++ ++mali_bool _mali_internal_profiling_is_recording(void) ++{ ++ return prof_state == MALI_PROFILING_STATE_RUNNING ? MALI_TRUE : MALI_FALSE; ++} ++ ++mali_bool _mali_internal_profiling_have_recording(void) ++{ ++ return prof_state == MALI_PROFILING_STATE_RETURN ? MALI_TRUE : MALI_FALSE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.h +new file mode 100644 +index 0000000..3c86e07 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_profiling_internal.h +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_PROFILING_INTERNAL_H__ ++#define __MALI_PROFILING_INTERNAL_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "mali_osk.h" ++ ++int _mali_internal_profiling_init(mali_bool auto_start); ++void _mali_internal_profiling_term(void); ++ ++mali_bool _mali_internal_profiling_is_recording(void); ++mali_bool _mali_internal_profiling_have_recording(void); ++_mali_osk_errcode_t _mali_internal_profiling_clear(void); ++_mali_osk_errcode_t _mali_internal_profiling_get_event(u32 index, u64* timestamp, u32* event_id, u32 data[5]); ++u32 _mali_internal_profiling_get_count(void); ++int _mali_internal_profiling_stop(u32 * count); ++int _mali_internal_profiling_start(u32 * limit); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_PROFILING_INTERNAL_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.c +new file mode 100644 +index 0000000..d85d5bb +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.c +@@ -0,0 +1,304 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_sync.h" ++ ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_timeline.h" ++ ++#include ++#include ++#include ++ ++struct mali_sync_pt { ++ struct sync_pt sync_pt; ++ struct mali_sync_flag *flag; ++}; ++ ++/** ++ * The sync flag is used to connect sync fences to the Mali Timeline system. Sync fences can be ++ * created from a sync flag, and when the flag is signaled, the sync fences will also be signaled. ++ */ ++struct mali_sync_flag { ++ struct sync_timeline *sync_tl; /**< Sync timeline this flag is connected to. */ ++ u32 point; /**< Point on timeline. */ ++ int status; /**< 0 if unsignaled, 1 if signaled without error or negative if signaled with error. */ ++ struct kref refcount; /**< Reference count. */ ++}; ++ ++MALI_STATIC_INLINE struct mali_sync_pt *to_mali_sync_pt(struct sync_pt *pt) ++{ ++ return container_of(pt, struct mali_sync_pt, sync_pt); ++} ++ ++static struct sync_pt *timeline_dup(struct sync_pt *pt) ++{ ++ struct mali_sync_pt *mpt, *new_mpt; ++ struct sync_pt *new_pt; ++ ++ MALI_DEBUG_ASSERT_POINTER(pt); ++ mpt = to_mali_sync_pt(pt); ++ ++ new_pt = sync_pt_create(pt->parent, sizeof(struct mali_sync_pt)); ++ if (NULL == new_pt) return NULL; ++ ++ new_mpt = to_mali_sync_pt(new_pt); ++ ++ mali_sync_flag_get(mpt->flag); ++ new_mpt->flag = mpt->flag; ++ ++ return new_pt; ++} ++ ++static int timeline_has_signaled(struct sync_pt *pt) ++{ ++ struct mali_sync_pt *mpt; ++ ++ MALI_DEBUG_ASSERT_POINTER(pt); ++ mpt = to_mali_sync_pt(pt); ++ ++ MALI_DEBUG_ASSERT_POINTER(mpt->flag); ++ ++ return mpt->flag->status; ++} ++ ++static int timeline_compare(struct sync_pt *pta, struct sync_pt *ptb) ++{ ++ struct mali_sync_pt *mpta; ++ struct mali_sync_pt *mptb; ++ u32 a, b; ++ ++ MALI_DEBUG_ASSERT_POINTER(pta); ++ MALI_DEBUG_ASSERT_POINTER(ptb); ++ mpta = to_mali_sync_pt(pta); ++ mptb = to_mali_sync_pt(ptb); ++ ++ MALI_DEBUG_ASSERT_POINTER(mpta->flag); ++ MALI_DEBUG_ASSERT_POINTER(mptb->flag); ++ ++ a = mpta->flag->point; ++ b = mpta->flag->point; ++ ++ if (a == b) return 0; ++ ++ return ((b - a) < (a - b) ? -1 : 1); ++} ++ ++static void timeline_free_pt(struct sync_pt *pt) ++{ ++ struct mali_sync_pt *mpt; ++ ++ MALI_DEBUG_ASSERT_POINTER(pt); ++ mpt = to_mali_sync_pt(pt); ++ ++ mali_sync_flag_put(mpt->flag); ++} ++ ++static void timeline_release(struct sync_timeline *sync_timeline) ++{ ++ module_put(THIS_MODULE); ++} ++ ++static void timeline_print_pt(struct seq_file *s, struct sync_pt *sync_pt) ++{ ++ struct mali_sync_pt *mpt; ++ ++ MALI_DEBUG_ASSERT_POINTER(s); ++ MALI_DEBUG_ASSERT_POINTER(sync_pt); ++ ++ mpt = to_mali_sync_pt(sync_pt); ++ MALI_DEBUG_ASSERT_POINTER(mpt->flag); ++ ++ seq_printf(s, "%u", mpt->flag->point); ++} ++ ++static struct sync_timeline_ops mali_timeline_ops = { ++ .driver_name = "Mali", ++ .dup = timeline_dup, ++ .has_signaled = timeline_has_signaled, ++ .compare = timeline_compare, ++ .free_pt = timeline_free_pt, ++ .release_obj = timeline_release, ++ .print_pt = timeline_print_pt, ++}; ++ ++struct sync_timeline *mali_sync_timeline_create(const char *name) ++{ ++ struct sync_timeline *sync_tl; ++ ++ sync_tl = sync_timeline_create(&mali_timeline_ops, sizeof(struct sync_timeline), name); ++ if (NULL == sync_tl) return NULL; ++ ++ /* Grab a reference on the module to ensure the callbacks are present ++ * as long some timeline exists. The reference is released when the ++ * timeline is freed. ++ * Since this function is called from a ioctl on an open file we know ++ * we already have a reference, so using __module_get is safe. */ ++ __module_get(THIS_MODULE); ++ ++ return sync_tl; ++} ++ ++mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl) ++{ ++ MALI_DEBUG_ASSERT_POINTER(sync_tl); ++ return (sync_tl->ops == &mali_timeline_ops) ? MALI_TRUE : MALI_FALSE; ++} ++ ++s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence) ++{ ++ s32 fd = -1; ++ ++ fd = get_unused_fd(); ++ if (fd < 0) { ++ sync_fence_put(sync_fence); ++ return -1; ++ } ++ sync_fence_install(sync_fence, fd); ++ ++ return fd; ++} ++ ++struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2) ++{ ++ struct sync_fence *sync_fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(sync_fence1); ++ MALI_DEBUG_ASSERT_POINTER(sync_fence1); ++ ++ sync_fence = sync_fence_merge("mali_merge_fence", sync_fence1, sync_fence2); ++ sync_fence_put(sync_fence1); ++ sync_fence_put(sync_fence2); ++ ++ return sync_fence; ++} ++ ++struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl) ++{ ++ struct mali_sync_flag *flag; ++ struct sync_fence *sync_fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(sync_tl); ++ ++ flag = mali_sync_flag_create(sync_tl, 0); ++ if (NULL == flag) return NULL; ++ ++ sync_fence = mali_sync_flag_create_fence(flag); ++ ++ mali_sync_flag_signal(flag, 0); ++ mali_sync_flag_put(flag); ++ ++ return sync_fence; ++} ++ ++struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, mali_timeline_point point) ++{ ++ struct mali_sync_flag *flag; ++ ++ if (NULL == sync_tl) return NULL; ++ ++ flag = _mali_osk_calloc(1, sizeof(*flag)); ++ if (NULL == flag) return NULL; ++ ++ flag->sync_tl = sync_tl; ++ flag->point = point; ++ ++ flag->status = 0; ++ kref_init(&flag->refcount); ++ ++ return flag; ++} ++ ++void mali_sync_flag_get(struct mali_sync_flag *flag) ++{ ++ MALI_DEBUG_ASSERT_POINTER(flag); ++ kref_get(&flag->refcount); ++} ++ ++/** ++ * Free sync flag. ++ * ++ * @param ref kref object embedded in sync flag that should be freed. ++ */ ++static void mali_sync_flag_free(struct kref *ref) ++{ ++ struct mali_sync_flag *flag; ++ ++ MALI_DEBUG_ASSERT_POINTER(ref); ++ flag = container_of(ref, struct mali_sync_flag, refcount); ++ ++ _mali_osk_free(flag); ++} ++ ++void mali_sync_flag_put(struct mali_sync_flag *flag) ++{ ++ MALI_DEBUG_ASSERT_POINTER(flag); ++ kref_put(&flag->refcount, mali_sync_flag_free); ++} ++ ++void mali_sync_flag_signal(struct mali_sync_flag *flag, int error) ++{ ++ MALI_DEBUG_ASSERT_POINTER(flag); ++ ++ MALI_DEBUG_ASSERT(0 == flag->status); ++ flag->status = (0 > error) ? error : 1; ++ ++ _mali_osk_write_mem_barrier(); ++ ++ sync_timeline_signal(flag->sync_tl); ++} ++ ++/** ++ * Create a sync point attached to given sync flag. ++ * ++ * @note Sync points must be triggered in *exactly* the same order as they are created. ++ * ++ * @param flag Sync flag. ++ * @return New sync point if successful, NULL if not. ++ */ ++static struct sync_pt *mali_sync_flag_create_pt(struct mali_sync_flag *flag) ++{ ++ struct sync_pt *pt; ++ struct mali_sync_pt *mpt; ++ ++ MALI_DEBUG_ASSERT_POINTER(flag); ++ MALI_DEBUG_ASSERT_POINTER(flag->sync_tl); ++ ++ pt = sync_pt_create(flag->sync_tl, sizeof(struct mali_sync_pt)); ++ if (NULL == pt) return NULL; ++ ++ mali_sync_flag_get(flag); ++ ++ mpt = to_mali_sync_pt(pt); ++ mpt->flag = flag; ++ ++ return pt; ++} ++ ++struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag) ++{ ++ struct sync_pt *sync_pt; ++ struct sync_fence *sync_fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(flag); ++ MALI_DEBUG_ASSERT_POINTER(flag->sync_tl); ++ ++ sync_pt = mali_sync_flag_create_pt(flag); ++ if (NULL == sync_pt) return NULL; ++ ++ sync_fence = sync_fence_create("mali_flag_fence", sync_pt); ++ if (NULL == sync_fence) { ++ sync_pt_free(sync_pt); ++ return NULL; ++ } ++ ++ return sync_fence; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.h +new file mode 100644 +index 0000000..6b131a6 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_sync.h +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_sync.h ++ * ++ * Mali interface for Linux sync objects. ++ */ ++ ++#ifndef _MALI_SYNC_H_ ++#define _MALI_SYNC_H_ ++ ++#if defined(CONFIG_SYNC) ++ ++#include ++#include ++ ++#include "mali_osk.h" ++ ++struct mali_sync_flag; ++ ++/** ++ * Create a sync timeline. ++ * ++ * @param name Name of the sync timeline. ++ * @return The new sync timeline if successful, NULL if not. ++ */ ++struct sync_timeline *mali_sync_timeline_create(const char *name); ++ ++/** ++ * Check if sync timeline belongs to Mali. ++ * ++ * @param sync_tl Sync timeline to check. ++ * @return MALI_TRUE if sync timeline belongs to Mali, MALI_FALSE if not. ++ */ ++mali_bool mali_sync_timeline_is_ours(struct sync_timeline *sync_tl); ++ ++/** ++ * Creates a file descriptor representing the sync fence. Will release sync fence if allocation of ++ * file descriptor fails. ++ * ++ * @param sync_fence Sync fence. ++ * @return File descriptor representing sync fence if successful, or -1 if not. ++ */ ++s32 mali_sync_fence_fd_alloc(struct sync_fence *sync_fence); ++ ++/** ++ * Merges two sync fences. Both input sync fences will be released. ++ * ++ * @param sync_fence1 First sync fence. ++ * @param sync_fence2 Second sync fence. ++ * @return New sync fence that is the result of the merger if successful, or NULL if not. ++ */ ++struct sync_fence *mali_sync_fence_merge(struct sync_fence *sync_fence1, struct sync_fence *sync_fence2); ++ ++/** ++ * Create a sync fence that is already signaled. ++ * ++ * @param tl Sync timeline. ++ * @return New signaled sync fence if successful, NULL if not. ++ */ ++struct sync_fence *mali_sync_timeline_create_signaled_fence(struct sync_timeline *sync_tl); ++ ++/** ++ * Create a sync flag. ++ * ++ * @param sync_tl Sync timeline. ++ * @param point Point on Mali timeline. ++ * @return New sync flag if successful, NULL if not. ++ */ ++struct mali_sync_flag *mali_sync_flag_create(struct sync_timeline *sync_tl, u32 point); ++ ++/** ++ * Grab sync flag reference. ++ * ++ * @param flag Sync flag. ++ */ ++void mali_sync_flag_get(struct mali_sync_flag *flag); ++ ++/** ++ * Release sync flag reference. If this was the last reference, the sync flag will be freed. ++ * ++ * @param flag Sync flag. ++ */ ++void mali_sync_flag_put(struct mali_sync_flag *flag); ++ ++/** ++ * Signal sync flag. All sync fences created from this flag will be signaled. ++ * ++ * @param flag Sync flag to signal. ++ * @param error Negative error code, or 0 if no error. ++ */ ++void mali_sync_flag_signal(struct mali_sync_flag *flag, int error); ++ ++/** ++ * Create a sync fence attached to given sync flag. ++ * ++ * @param flag Sync flag. ++ * @return New sync fence if successful, NULL if not. ++ */ ++struct sync_fence *mali_sync_flag_create_fence(struct mali_sync_flag *flag); ++ ++#endif /* defined(CONFIG_SYNC) */ ++ ++#endif /* _MALI_SYNC_H_ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_uk_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_uk_types.h +new file mode 100644 +index 0000000..fbe902a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_uk_types.h +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2012 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_UK_TYPES_H__ ++#define __MALI_UK_TYPES_H__ ++ ++/* Simple wrapper in order to find the OS specific location of this file */ ++#include ++ ++#endif /* __MALI_UK_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_core.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_core.c +new file mode 100644 +index 0000000..c0372d7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_core.c +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* memort allocation functions */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs) ++{ ++ _mali_uk_get_api_version_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != get_user(kargs.version, &uargs->version)) return -EFAULT; ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_get_api_version(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT; ++ if (0 != put_user(kargs.compatible, &uargs->compatible)) return -EFAULT; ++ ++ return 0; ++} ++ ++int wait_for_notification_wrapper(struct mali_session_data *session_data, _mali_uk_wait_for_notification_s __user *uargs) ++{ ++ _mali_uk_wait_for_notification_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_wait_for_notification(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ if(_MALI_NOTIFICATION_CORE_SHUTDOWN_IN_PROGRESS != kargs.type) { ++ kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ ++ if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_wait_for_notification_s))) return -EFAULT; ++ } else { ++ if (0 != put_user(kargs.type, &uargs->type)) return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_post_notification_s __user *uargs) ++{ ++ _mali_uk_post_notification_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ ++ if (0 != get_user(kargs.type, &uargs->type)) { ++ return -EFAULT; ++ } ++ ++ err = _mali_ukk_post_notification(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ return 0; ++} ++ ++int get_user_settings_wrapper(struct mali_session_data *session_data, _mali_uk_get_user_settings_s __user *uargs) ++{ ++ _mali_uk_get_user_settings_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_get_user_settings(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ ++ if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_get_user_settings_s))) return -EFAULT; ++ ++ return 0; ++} ++ ++int request_high_priority_wrapper(struct mali_session_data *session_data, _mali_uk_request_high_priority_s __user *uargs) ++{ ++ _mali_uk_request_high_priority_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_request_high_priority(&kargs); ++ ++ kargs.ctx = NULL; ++ ++ return map_errcode(err); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_gp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_gp.c +new file mode 100644 +index 0000000..32b148b +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_gp.c +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs) ++{ ++ _mali_osk_errcode_t err; ++ ++ /* If the job was started successfully, 0 is returned. If there was an error, but the job ++ * was started, we return -ENOENT. For anything else returned, the job was not started. */ ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ err = _mali_ukk_gp_start_job(session_data, uargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ return 0; ++} ++ ++int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs) ++{ ++ _mali_uk_get_gp_core_version_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_get_gp_core_version(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ /* no known transactions to roll-back */ ++ ++ if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT; ++ ++ return 0; ++} ++ ++int gp_suspend_response_wrapper(struct mali_session_data *session_data, _mali_uk_gp_suspend_response_s __user *uargs) ++{ ++ _mali_uk_gp_suspend_response_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_gp_suspend_response_s))) return -EFAULT; ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_gp_suspend_response(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ if (0 != put_user(kargs.cookie, &uargs->cookie)) return -EFAULT; ++ ++ /* no known transactions to roll-back */ ++ return 0; ++} ++ ++int gp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_number_of_cores_s __user *uargs) ++{ ++ _mali_uk_get_gp_number_of_cores_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_get_gp_number_of_cores(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ /* no known transactions to roll-back */ ++ ++ if (0 != put_user(kargs.number_of_cores, &uargs->number_of_cores)) return -EFAULT; ++ ++ return 0; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_mem.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_mem.c +new file mode 100644 +index 0000000..083c909 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_mem.c +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_write_safe_s __user * uargs) ++{ ++ _mali_uk_mem_write_safe_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_mem_write_safe_s))) { ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ ++ /* Check if we can access the buffers */ ++ if (!access_ok(VERIFY_WRITE, kargs.dest, kargs.size) ++ || !access_ok(VERIFY_READ, kargs.src, kargs.size)) { ++ return -EINVAL; ++ } ++ ++ /* Check if size wraps */ ++ if ((kargs.size + kargs.dest) <= kargs.dest ++ || (kargs.size + kargs.src) <= kargs.src) { ++ return -EINVAL; ++ } ++ ++ err = _mali_ukk_mem_write_safe(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ if (0 != put_user(kargs.size, &uargs->size)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user * argument) ++{ ++ _mali_uk_map_external_mem_s uk_args; ++ _mali_osk_errcode_t err_code; ++ ++ /* validate input */ ++ /* the session_data pointer was validated by caller */ ++ MALI_CHECK_NON_NULL( argument, -EINVAL); ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_map_external_mem_s)) ) { ++ return -EFAULT; ++ } ++ ++ uk_args.ctx = session_data; ++ err_code = _mali_ukk_map_external_mem( &uk_args ); ++ ++ if (0 != put_user(uk_args.cookie, &argument->cookie)) { ++ if (_MALI_OSK_ERR_OK == err_code) { ++ /* Rollback */ ++ _mali_uk_unmap_external_mem_s uk_args_unmap; ++ ++ uk_args_unmap.ctx = session_data; ++ uk_args_unmap.cookie = uk_args.cookie; ++ err_code = _mali_ukk_unmap_external_mem( &uk_args_unmap ); ++ if (_MALI_OSK_ERR_OK != err_code) { ++ MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_unmap_external_mem, as a result of failing put_user(), failed\n")); ++ } ++ } ++ return -EFAULT; ++ } ++ ++ /* Return the error that _mali_ukk_free_big_block produced */ ++ return map_errcode(err_code); ++} ++ ++int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user * argument) ++{ ++ _mali_uk_unmap_external_mem_s uk_args; ++ _mali_osk_errcode_t err_code; ++ ++ /* validate input */ ++ /* the session_data pointer was validated by caller */ ++ MALI_CHECK_NON_NULL( argument, -EINVAL); ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_unmap_external_mem_s)) ) { ++ return -EFAULT; ++ } ++ ++ uk_args.ctx = session_data; ++ err_code = _mali_ukk_unmap_external_mem( &uk_args ); ++ ++ /* Return the error that _mali_ukk_free_big_block produced */ ++ return map_errcode(err_code); ++} ++ ++#if defined(CONFIG_MALI400_UMP) ++int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument) ++{ ++ _mali_uk_release_ump_mem_s uk_args; ++ _mali_osk_errcode_t err_code; ++ ++ /* validate input */ ++ /* the session_data pointer was validated by caller */ ++ MALI_CHECK_NON_NULL( argument, -EINVAL); ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_release_ump_mem_s)) ) { ++ return -EFAULT; ++ } ++ ++ uk_args.ctx = session_data; ++ err_code = _mali_ukk_release_ump_mem( &uk_args ); ++ ++ /* Return the error that _mali_ukk_free_big_block produced */ ++ return map_errcode(err_code); ++} ++ ++int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user * argument) ++{ ++ _mali_uk_attach_ump_mem_s uk_args; ++ _mali_osk_errcode_t err_code; ++ ++ /* validate input */ ++ /* the session_data pointer was validated by caller */ ++ MALI_CHECK_NON_NULL( argument, -EINVAL); ++ ++ /* get call arguments from user space. copy_from_user returns how many bytes which where NOT copied */ ++ if ( 0 != copy_from_user(&uk_args, (void __user *)argument, sizeof(_mali_uk_attach_ump_mem_s)) ) { ++ return -EFAULT; ++ } ++ ++ uk_args.ctx = session_data; ++ err_code = _mali_ukk_attach_ump_mem( &uk_args ); ++ ++ if (0 != put_user(uk_args.cookie, &argument->cookie)) { ++ if (_MALI_OSK_ERR_OK == err_code) { ++ /* Rollback */ ++ _mali_uk_release_ump_mem_s uk_args_unmap; ++ ++ uk_args_unmap.ctx = session_data; ++ uk_args_unmap.cookie = uk_args.cookie; ++ err_code = _mali_ukk_release_ump_mem( &uk_args_unmap ); ++ if (_MALI_OSK_ERR_OK != err_code) { ++ MALI_DEBUG_PRINT(4, ("reverting _mali_ukk_attach_mem, as a result of failing put_user(), failed\n")); ++ } ++ } ++ return -EFAULT; ++ } ++ ++ /* Return the error that _mali_ukk_map_external_ump_mem produced */ ++ return map_errcode(err_code); ++} ++#endif /* CONFIG_MALI400_UMP */ ++ ++int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user * uargs) ++{ ++ _mali_uk_query_mmu_page_table_dump_size_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ kargs.ctx = session_data; ++ ++ err = _mali_ukk_query_mmu_page_table_dump_size(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ if (0 != put_user(kargs.size, &uargs->size)) return -EFAULT; ++ ++ return 0; ++} ++ ++int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user * uargs) ++{ ++ _mali_uk_dump_mmu_page_table_s kargs; ++ _mali_osk_errcode_t err; ++ void *buffer; ++ int rc = -EFAULT; ++ ++ /* validate input */ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ /* the session_data pointer was validated by caller */ ++ ++ kargs.buffer = NULL; ++ ++ /* get location of user buffer */ ++ if (0 != get_user(buffer, &uargs->buffer)) goto err_exit; ++ /* get size of mmu page table info buffer from user space */ ++ if ( 0 != get_user(kargs.size, &uargs->size) ) goto err_exit; ++ /* verify we can access the whole of the user buffer */ ++ if (!access_ok(VERIFY_WRITE, buffer, kargs.size)) goto err_exit; ++ ++ /* allocate temporary buffer (kernel side) to store mmu page table info */ ++ MALI_CHECK(kargs.size > 0, -ENOMEM); ++ kargs.buffer = _mali_osk_valloc(kargs.size); ++ if (NULL == kargs.buffer) { ++ rc = -ENOMEM; ++ goto err_exit; ++ } ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_dump_mmu_page_table(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ rc = map_errcode(err); ++ goto err_exit; ++ } ++ ++ /* copy mmu page table info back to user space and update pointers */ ++ if (0 != copy_to_user(uargs->buffer, kargs.buffer, kargs.size) ) goto err_exit; ++ if (0 != put_user((kargs.register_writes - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->register_writes)) goto err_exit; ++ if (0 != put_user((kargs.page_table_dump - (u32 *)kargs.buffer) + (u32 *)uargs->buffer, &uargs->page_table_dump)) goto err_exit; ++ if (0 != put_user(kargs.register_writes_size, &uargs->register_writes_size)) goto err_exit; ++ if (0 != put_user(kargs.page_table_dump_size, &uargs->page_table_dump_size)) goto err_exit; ++ rc = 0; ++ ++err_exit: ++ if (kargs.buffer) _mali_osk_vfree(kargs.buffer); ++ return rc; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_pp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_pp.c +new file mode 100644 +index 0000000..e5126ec +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_pp.c +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs) ++{ ++ _mali_osk_errcode_t err; ++ ++ /* If the job was started successfully, 0 is returned. If there was an error, but the job ++ * was started, we return -ENOENT. For anything else returned, the job was not started. */ ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ err = _mali_ukk_pp_start_job(session_data, uargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ return 0; ++} ++ ++int pp_and_gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_and_gp_start_job_s __user *uargs) ++{ ++ _mali_osk_errcode_t err; ++ ++ /* If the jobs were started successfully, 0 is returned. If there was an error, but the ++ * jobs were started, we return -ENOENT. For anything else returned, the jobs were not ++ * started. */ ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ err = _mali_ukk_pp_and_gp_start_job(session_data, uargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ return 0; ++} ++ ++int pp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_number_of_cores_s __user *uargs) ++{ ++ _mali_uk_get_pp_number_of_cores_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ kargs.ctx = session_data; ++ ++ err = _mali_ukk_get_pp_number_of_cores(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ ++ if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_get_pp_number_of_cores_s))) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_core_version_s __user *uargs) ++{ ++ _mali_uk_get_pp_core_version_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_get_pp_core_version(&kargs); ++ if (_MALI_OSK_ERR_OK != err) return map_errcode(err); ++ ++ if (0 != put_user(kargs.version, &uargs->version)) return -EFAULT; ++ ++ return 0; ++} ++ ++int pp_disable_wb_wrapper(struct mali_session_data *session_data, _mali_uk_pp_disable_wb_s __user *uargs) ++{ ++ _mali_uk_pp_disable_wb_s kargs; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session_data, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_pp_disable_wb_s))) return -EFAULT; ++ ++ kargs.ctx = session_data; ++ _mali_ukk_pp_job_disable_wb(&kargs); ++ ++ return 0; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_profiling.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_profiling.c +new file mode 100644 +index 0000000..8423f28 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_profiling.c +@@ -0,0 +1,168 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++#include ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++int profiling_start_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_start_s __user *uargs) ++{ ++ _mali_uk_profiling_start_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_profiling_start_s))) { ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_profiling_start(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ if (0 != put_user(kargs.limit, &uargs->limit)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int profiling_add_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_add_event_s __user *uargs) ++{ ++ _mali_uk_profiling_add_event_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_profiling_add_event_s))) { ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_profiling_add_event(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ return 0; ++} ++ ++int profiling_stop_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_stop_s __user *uargs) ++{ ++ _mali_uk_profiling_stop_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_profiling_stop(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ if (0 != put_user(kargs.count, &uargs->count)) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int profiling_get_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_event_s __user *uargs) ++{ ++ _mali_uk_profiling_get_event_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != get_user(kargs.index, &uargs->index)) { ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ ++ err = _mali_ukk_profiling_get_event(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ kargs.ctx = NULL; /* prevent kernel address to be returned to user space */ ++ if (0 != copy_to_user(uargs, &kargs, sizeof(_mali_uk_profiling_get_event_s))) { ++ return -EFAULT; ++ } ++ ++ return 0; ++} ++ ++int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_clear_s __user *uargs) ++{ ++ _mali_uk_profiling_clear_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_profiling_clear(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ return 0; ++} ++ ++int profiling_report_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_report_s __user *uargs) ++{ ++ _mali_uk_sw_counters_report_s kargs; ++ _mali_osk_errcode_t err; ++ u32 *counter_buffer; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_sw_counters_report_s))) { ++ return -EFAULT; ++ } ++ ++ /* make sure that kargs.num_counters is [at least somewhat] sane */ ++ if (kargs.num_counters > 10000) { ++ MALI_DEBUG_PRINT(1, ("User space attempted to allocate too many counters.\n")); ++ return -EINVAL; ++ } ++ ++ counter_buffer = (u32*)kmalloc(sizeof(u32) * kargs.num_counters, GFP_KERNEL); ++ if (NULL == counter_buffer) { ++ return -ENOMEM; ++ } ++ ++ if (0 != copy_from_user(counter_buffer, kargs.counters, sizeof(u32) * kargs.num_counters)) { ++ kfree(counter_buffer); ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ kargs.counters = counter_buffer; ++ ++ err = _mali_ukk_sw_counters_report(&kargs); ++ ++ kfree(counter_buffer); ++ ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ return 0; ++} ++ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_soft_job.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_soft_job.c +new file mode 100644 +index 0000000..51ef466 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_soft_job.c +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++#include "mali_soft_job.h" ++#include "mali_timeline.h" ++ ++int soft_job_start_wrapper(struct mali_session_data *session, _mali_uk_soft_job_start_s __user *uargs) ++{ ++ u32 type, user_job, point; ++ _mali_uk_fence_t uk_fence; ++ struct mali_timeline_fence fence; ++ struct mali_soft_job *job = NULL; ++ u32 __user *job_id_ptr = NULL; ++ ++ /* If the job was started successfully, 0 is returned. If there was an error, but the job ++ * was started, we return -ENOENT. For anything else returned, the job was not started. */ ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ MALI_CHECK_NON_NULL(session, -EINVAL); ++ ++ MALI_DEBUG_ASSERT_POINTER(session->soft_job_system); ++ ++ if (0 != get_user(type, &uargs->type)) return -EFAULT; ++ if (0 != get_user(user_job, &uargs->user_job)) return -EFAULT; ++ if (0 != get_user(job_id_ptr, &uargs->job_id_ptr)) return -EFAULT; ++ ++ if (0 != copy_from_user(&uk_fence, &uargs->fence, sizeof(_mali_uk_fence_t))) return -EFAULT; ++ mali_timeline_fence_copy_uk_fence(&fence, &uk_fence); ++ ++ if (MALI_SOFT_JOB_TYPE_USER_SIGNALED < type) { ++ MALI_DEBUG_PRINT_ERROR(("Invalid soft job type specified\n")); ++ return -EINVAL; ++ } ++ ++ /* Create soft job. */ ++ job = mali_soft_job_create(session->soft_job_system, (enum mali_soft_job_type)type, user_job); ++ if (unlikely(NULL == job)) { ++ return map_errcode(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ /* Write job id back to user space. */ ++ if (0 != put_user(job->id, job_id_ptr)) { ++ MALI_PRINT_ERROR(("Mali Soft Job: failed to put job id")); ++ mali_soft_job_destroy(job); ++ return map_errcode(_MALI_OSK_ERR_NOMEM); ++ } ++ ++ /* Start soft job. */ ++ point = mali_soft_job_start(job, &fence); ++ ++ if (0 != put_user(point, &uargs->point)) { ++ /* Let user space know that something failed after the job was started. */ ++ return -ENOENT; ++ } ++ ++ return 0; ++} ++ ++int soft_job_signal_wrapper(struct mali_session_data *session, _mali_uk_soft_job_signal_s __user *uargs) ++{ ++ u32 job_id; ++ _mali_osk_errcode_t err; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ if (0 != get_user(job_id, &uargs->job_id)) return -EFAULT; ++ ++ err = mali_soft_job_system_signal_job(session->soft_job_system, job_id); ++ ++ return map_errcode(err); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_timeline.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_timeline.c +new file mode 100644 +index 0000000..dd72dee +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_timeline.c +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++#include "mali_timeline.h" ++#include "mali_timeline_fence_wait.h" ++#include "mali_timeline_sync_fence.h" ++ ++int timeline_get_latest_point_wrapper(struct mali_session_data *session, _mali_uk_timeline_get_latest_point_s __user *uargs) ++{ ++ u32 val; ++ mali_timeline_id timeline; ++ mali_timeline_point point; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ if (0 != get_user(val, &uargs->timeline)) return -EFAULT; ++ ++ if (MALI_UK_TIMELINE_MAX <= val) { ++ return -EINVAL; ++ } ++ ++ timeline = (mali_timeline_id)val; ++ ++ point = mali_timeline_system_get_latest_point(session->timeline_system, timeline); ++ ++ if (0 != put_user(point, &uargs->point)) return -EFAULT; ++ ++ return 0; ++} ++ ++int timeline_wait_wrapper(struct mali_session_data *session, _mali_uk_timeline_wait_s __user *uargs) ++{ ++ u32 timeout, status; ++ mali_bool ret; ++ _mali_uk_fence_t uk_fence; ++ struct mali_timeline_fence fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ if (0 != copy_from_user(&uk_fence, &uargs->fence, sizeof(_mali_uk_fence_t))) return -EFAULT; ++ if (0 != get_user(timeout, &uargs->timeout)) return -EFAULT; ++ ++ mali_timeline_fence_copy_uk_fence(&fence, &uk_fence); ++ ++ ret = mali_timeline_fence_wait(session->timeline_system, &fence, timeout); ++ status = (MALI_TRUE == ret ? 1 : 0); ++ ++ if (0 != put_user(status, &uargs->status)) return -EFAULT; ++ ++ return 0; ++} ++ ++int timeline_create_sync_fence_wrapper(struct mali_session_data *session, _mali_uk_timeline_create_sync_fence_s __user *uargs) ++{ ++ s32 sync_fd = -1; ++ _mali_uk_fence_t uk_fence; ++ struct mali_timeline_fence fence; ++ ++ MALI_DEBUG_ASSERT_POINTER(session); ++ ++ if (0 != copy_from_user(&uk_fence, &uargs->fence, sizeof(_mali_uk_fence_t))) return -EFAULT; ++ mali_timeline_fence_copy_uk_fence(&fence, &uk_fence); ++ ++#if defined(CONFIG_SYNC) ++ sync_fd = mali_timeline_sync_fence_create(session->timeline_system, &fence); ++#else ++ sync_fd = -1; ++#endif /* defined(CONFIG_SYNC) */ ++ ++ if (0 != put_user(sync_fd, &uargs->sync_fd)) return -EFAULT; ++ ++ return 0; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_vsync.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_vsync.c +new file mode 100644 +index 0000000..276a147 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_vsync.c +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (C) 2011-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++#include /* file system operations */ ++#include /* user space access */ ++ ++#include "mali_ukk.h" ++#include "mali_osk.h" ++#include "mali_kernel_common.h" ++#include "mali_session.h" ++#include "mali_ukk_wrappers.h" ++ ++ ++int vsync_event_report_wrapper(struct mali_session_data *session_data, _mali_uk_vsync_event_report_s __user *uargs) ++{ ++ _mali_uk_vsync_event_report_s kargs; ++ _mali_osk_errcode_t err; ++ ++ MALI_CHECK_NON_NULL(uargs, -EINVAL); ++ ++ if (0 != copy_from_user(&kargs, uargs, sizeof(_mali_uk_vsync_event_report_s))) { ++ return -EFAULT; ++ } ++ ++ kargs.ctx = session_data; ++ err = _mali_ukk_vsync_event_report(&kargs); ++ if (_MALI_OSK_ERR_OK != err) { ++ return map_errcode(err); ++ } ++ ++ return 0; ++} ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_wrappers.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_wrappers.h +new file mode 100644 +index 0000000..0883b6c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/linux/mali_ukk_wrappers.h +@@ -0,0 +1,75 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_ukk_wrappers.h ++ * Defines the wrapper functions for each user-kernel function ++ */ ++ ++#ifndef __MALI_UKK_WRAPPERS_H__ ++#define __MALI_UKK_WRAPPERS_H__ ++ ++#include "mali_uk_types.h" ++#include "mali_osk.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int wait_for_notification_wrapper(struct mali_session_data *session_data, _mali_uk_wait_for_notification_s __user *uargs); ++int get_api_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_api_version_s __user *uargs); ++int get_user_settings_wrapper(struct mali_session_data *session_data, _mali_uk_get_user_settings_s __user *uargs); ++int post_notification_wrapper(struct mali_session_data *session_data, _mali_uk_post_notification_s __user *uargs); ++int request_high_priority_wrapper(struct mali_session_data *session_data, _mali_uk_request_high_priority_s __user *uargs); ++ ++int mem_write_safe_wrapper(struct mali_session_data *session_data, _mali_uk_mem_write_safe_s __user * uargs); ++int mem_map_ext_wrapper(struct mali_session_data *session_data, _mali_uk_map_external_mem_s __user * argument); ++int mem_unmap_ext_wrapper(struct mali_session_data *session_data, _mali_uk_unmap_external_mem_s __user * argument); ++int mem_query_mmu_page_table_dump_size_wrapper(struct mali_session_data *session_data, _mali_uk_query_mmu_page_table_dump_size_s __user * uargs); ++int mem_dump_mmu_page_table_wrapper(struct mali_session_data *session_data, _mali_uk_dump_mmu_page_table_s __user * uargs); ++ ++int timeline_get_latest_point_wrapper(struct mali_session_data *session, _mali_uk_timeline_get_latest_point_s __user *uargs); ++int timeline_wait_wrapper(struct mali_session_data *session, _mali_uk_timeline_wait_s __user *uargs); ++int timeline_create_sync_fence_wrapper(struct mali_session_data *session, _mali_uk_timeline_create_sync_fence_s __user *uargs); ++int soft_job_start_wrapper(struct mali_session_data *session, _mali_uk_soft_job_start_s __user *uargs); ++int soft_job_signal_wrapper(struct mali_session_data *session, _mali_uk_soft_job_signal_s __user *uargs); ++ ++#if defined(CONFIG_MALI400_UMP) ++int mem_attach_ump_wrapper(struct mali_session_data *session_data, _mali_uk_attach_ump_mem_s __user * argument); ++int mem_release_ump_wrapper(struct mali_session_data *session_data, _mali_uk_release_ump_mem_s __user * argument); ++#endif ++ ++int pp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_start_job_s __user *uargs); ++int pp_and_gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_pp_and_gp_start_job_s __user *uargs); ++int pp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_number_of_cores_s __user *uargs); ++int pp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_pp_core_version_s __user *uargs); ++int pp_disable_wb_wrapper(struct mali_session_data *session_data, _mali_uk_pp_disable_wb_s __user *uargs); ++int gp_start_job_wrapper(struct mali_session_data *session_data, _mali_uk_gp_start_job_s __user *uargs); ++int gp_get_number_of_cores_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_number_of_cores_s __user *uargs); ++int gp_get_core_version_wrapper(struct mali_session_data *session_data, _mali_uk_get_gp_core_version_s __user *uargs); ++int gp_suspend_response_wrapper(struct mali_session_data *session_data, _mali_uk_gp_suspend_response_s __user *uargs); ++ ++int profiling_start_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_start_s __user *uargs); ++int profiling_add_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_add_event_s __user *uargs); ++int profiling_stop_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_stop_s __user *uargs); ++int profiling_get_event_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_get_event_s __user *uargs); ++int profiling_clear_wrapper(struct mali_session_data *session_data, _mali_uk_profiling_clear_s __user *uargs); ++int profiling_report_sw_counters_wrapper(struct mali_session_data *session_data, _mali_uk_sw_counters_report_s __user *uargs); ++ ++int vsync_event_report_wrapper(struct mali_session_data *session_data, _mali_uk_vsync_event_report_s __user *uargs); ++ ++ ++int map_errcode( _mali_osk_errcode_t err ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __MALI_UKK_WRAPPERS_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm.c +new file mode 100644 +index 0000000..7ab66ce +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm.c +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file mali_platform.c ++ * Platform specific Mali driver functions for: ++ * - Realview Versatile platforms with ARM11 Mpcore and virtex 5. ++ * - Versatile Express platforms with ARM Cortex-A9 and virtex 6. ++ */ ++#include ++#include ++#include ++#ifdef CONFIG_PM_RUNTIME ++#include ++#endif ++#include ++#include ++#include "mali_kernel_common.h" ++#include ++#include ++ ++#include "arm_core_scaling.h" ++#include "mali_pp_scheduler.h" ++ ++static void mali_platform_device_release(struct device *device); ++static u32 mali_read_phys(u32 phys_addr); ++#if defined(CONFIG_ARCH_REALVIEW) ++static void mali_write_phys(u32 phys_addr, u32 value); ++#endif ++ ++static int mali_core_scaling_enable = 1; ++ ++void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data); ++ ++#if defined(CONFIG_ARCH_VEXPRESS) ++ ++static struct resource mali_gpu_resources_m450_mp8[] = { ++ MALI_GPU_RESOURCES_MALI450_MP8_PMU(0xFC040000, -1, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 68) ++}; ++ ++#elif defined(CONFIG_ARCH_REALVIEW) ++ ++static struct resource mali_gpu_resources_m300[] = { ++ MALI_GPU_RESOURCES_MALI300_PMU(0xC0000000, -1, -1, -1, -1) ++}; ++ ++static struct resource mali_gpu_resources_m400_mp1[] = { ++ MALI_GPU_RESOURCES_MALI400_MP1_PMU(0xC0000000, -1, -1, -1, -1) ++}; ++ ++static struct resource mali_gpu_resources_m400_mp2[] = { ++ MALI_GPU_RESOURCES_MALI400_MP2_PMU(0xC0000000, -1, -1, -1, -1, -1, -1) ++}; ++ ++#endif ++ ++static struct mali_gpu_device_data mali_gpu_data = { ++#if defined(CONFIG_ARCH_VEXPRESS) ++ .shared_mem_size =256 * 1024 * 1024, /* 256MB */ ++#elif defined(CONFIG_ARCH_REALVIEW) ++ .dedicated_mem_start = 0x80000000, /* Physical start address (use 0xD0000000 for old indirect setup) */ ++ .dedicated_mem_size = 0x10000000, /* 256MB */ ++#endif ++ .fb_start = 0xe0000000, ++ .fb_size = 0x01000000, ++ .max_job_runtime = 60000, /* 60 seconds */ ++ .utilization_interval = 1000, /* 1000ms */ ++ .utilization_callback = mali_gpu_utilization_callback, ++ .pmu_switch_delay = 0xFF, /* do not have to be this high on FPGA, but it is good for testing to have a delay */ ++ .pmu_domain_config = {0x1, 0x2, 0x4, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0x1, 0x2, 0x8}, ++}; ++ ++static struct platform_device mali_gpu_device = { ++ .name = MALI_GPU_NAME_UTGARD, ++ .id = 0, ++ .dev.release = mali_platform_device_release, ++ .dev.coherent_dma_mask = DMA_BIT_MASK(32), ++ ++ .dev.platform_data = &mali_gpu_data, ++}; ++ ++int mali_platform_device_register(void) ++{ ++ int err = -1; ++ int num_pp_cores = 0; ++#if defined(CONFIG_ARCH_REALVIEW) ++ u32 m400_gp_version; ++#endif ++ ++ MALI_DEBUG_PRINT(4, ("mali_platform_device_register() called\n")); ++ ++ /* Detect present Mali GPU and connect the correct resources to the device */ ++#if defined(CONFIG_ARCH_VEXPRESS) ++ ++ if (mali_read_phys(0xFC020000) == 0x00010100) { ++ MALI_DEBUG_PRINT(4, ("Registering Mali-450 MP8 device\n")); ++ num_pp_cores = 8; ++ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m450_mp8); ++ mali_gpu_device.resource = mali_gpu_resources_m450_mp8; ++ } ++ ++#elif defined(CONFIG_ARCH_REALVIEW) ++ ++ m400_gp_version = mali_read_phys(0xC000006C); ++ if ((m400_gp_version & 0xFFFF0000) == 0x0C070000) { ++ MALI_DEBUG_PRINT(4, ("Registering Mali-300 device\n")); ++ num_pp_cores = 1; ++ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m300); ++ mali_gpu_device.resource = mali_gpu_resources_m300; ++ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */ ++ } else if ((m400_gp_version & 0xFFFF0000) == 0x0B070000) { ++ u32 fpga_fw_version = mali_read_phys(0xC0010000); ++ if (fpga_fw_version == 0x130C008F || fpga_fw_version == 0x110C008F) { ++ /* Mali-400 MP1 r1p0 or r1p1 */ ++ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP1 device\n")); ++ num_pp_cores = 1; ++ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m400_mp1); ++ mali_gpu_device.resource = mali_gpu_resources_m400_mp1; ++ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */ ++ } else if (fpga_fw_version == 0x130C000F) { ++ /* Mali-400 MP2 r1p1 */ ++ MALI_DEBUG_PRINT(4, ("Registering Mali-400 MP2 device\n")); ++ num_pp_cores = 2; ++ mali_gpu_device.num_resources = ARRAY_SIZE(mali_gpu_resources_m400_mp2); ++ mali_gpu_device.resource = mali_gpu_resources_m400_mp2; ++ mali_write_phys(0xC0010020, 0xA); /* Enable direct memory mapping for FPGA */ ++ } ++ } ++ ++#endif ++ /* Register the platform device */ ++ err = platform_device_register(&mali_gpu_device); ++ if (0 == err) { ++#ifdef CONFIG_PM_RUNTIME ++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) ++ pm_runtime_set_autosuspend_delay(&(mali_gpu_device.dev), 1000); ++ pm_runtime_use_autosuspend(&(mali_gpu_device.dev)); ++#endif ++ pm_runtime_enable(&(mali_gpu_device.dev)); ++#endif ++ MALI_DEBUG_ASSERT(0 < num_pp_cores); ++ mali_core_scaling_init(num_pp_cores); ++ ++ return 0; ++ } ++ ++ return err; ++} ++ ++void mali_platform_device_unregister(void) ++{ ++ MALI_DEBUG_PRINT(4, ("mali_platform_device_unregister() called\n")); ++ ++ mali_core_scaling_term(); ++ platform_device_unregister(&mali_gpu_device); ++ ++ platform_device_put(&mali_gpu_device); ++ ++#if defined(CONFIG_ARCH_REALVIEW) ++ mali_write_phys(0xC0010020, 0x9); /* Restore default (legacy) memory mapping */ ++#endif ++} ++ ++static void mali_platform_device_release(struct device *device) ++{ ++ MALI_DEBUG_PRINT(4, ("mali_platform_device_release() called\n")); ++} ++ ++static u32 mali_read_phys(u32 phys_addr) ++{ ++ u32 phys_addr_page = phys_addr & 0xFFFFE000; ++ u32 phys_offset = phys_addr & 0x00001FFF; ++ u32 map_size = phys_offset + sizeof(u32); ++ u32 ret = 0xDEADBEEF; ++ void *mem_mapped = ioremap_nocache(phys_addr_page, map_size); ++ if (NULL != mem_mapped) { ++ ret = (u32)ioread32(((u8*)mem_mapped) + phys_offset); ++ iounmap(mem_mapped); ++ } ++ ++ return ret; ++} ++ ++#if defined(CONFIG_ARCH_REALVIEW) ++static void mali_write_phys(u32 phys_addr, u32 value) ++{ ++ u32 phys_addr_page = phys_addr & 0xFFFFE000; ++ u32 phys_offset = phys_addr & 0x00001FFF; ++ u32 map_size = phys_offset + sizeof(u32); ++ void *mem_mapped = ioremap_nocache(phys_addr_page, map_size); ++ if (NULL != mem_mapped) { ++ iowrite32(value, ((u8*)mem_mapped) + phys_offset); ++ iounmap(mem_mapped); ++ } ++} ++#endif ++ ++static int param_set_core_scaling(const char *val, const struct kernel_param *kp) ++{ ++ int ret = param_set_int(val, kp); ++ ++ if (1 == mali_core_scaling_enable) { ++ mali_core_scaling_sync(mali_pp_scheduler_get_num_cores_enabled()); ++ } ++ return ret; ++} ++ ++static struct kernel_param_ops param_ops_core_scaling = { ++ .set = param_set_core_scaling, ++ .get = param_get_int, ++}; ++ ++module_param_cb(mali_core_scaling_enable, ¶m_ops_core_scaling, &mali_core_scaling_enable, 0644); ++MODULE_PARM_DESC(mali_core_scaling_enable, "1 means to enable core scaling policy, 0 means to disable core scaling policy"); ++ ++void mali_gpu_utilization_callback(struct mali_gpu_utilization_data *data) ++{ ++ if (1 == mali_core_scaling_enable) { ++ mali_core_scaling_update(data); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.c +new file mode 100644 +index 0000000..b5dbdc9 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.c +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file arm_core_scaling.c ++ * Example core scaling policy. ++ */ ++ ++#include "arm_core_scaling.h" ++ ++#include ++#include "mali_kernel_common.h" ++ ++#include ++ ++static int num_cores_total; ++static int num_cores_enabled; ++ ++static struct work_struct wq_work; ++ ++static void set_num_cores(struct work_struct *work) ++{ ++ int err = mali_perf_set_num_pp_cores(num_cores_enabled); ++ MALI_DEBUG_ASSERT(0 == err); ++ MALI_IGNORE(err); ++} ++ ++static void enable_one_core(void) ++{ ++ if (num_cores_enabled < num_cores_total) { ++ ++num_cores_enabled; ++ schedule_work(&wq_work); ++ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling one more core\n")); ++ } ++ ++ MALI_DEBUG_ASSERT( 1 <= num_cores_enabled); ++ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled); ++} ++ ++static void disable_one_core(void) ++{ ++ if (1 < num_cores_enabled) { ++ --num_cores_enabled; ++ schedule_work(&wq_work); ++ MALI_DEBUG_PRINT(3, ("Core scaling: Disabling one core\n")); ++ } ++ ++ MALI_DEBUG_ASSERT( 1 <= num_cores_enabled); ++ MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled); ++} ++ ++static void enable_max_num_cores(void) ++{ ++ if (num_cores_enabled < num_cores_total) { ++ num_cores_enabled = num_cores_total; ++ schedule_work(&wq_work); ++ MALI_DEBUG_PRINT(3, ("Core scaling: Enabling maximum number of cores\n")); ++ } ++ ++ MALI_DEBUG_ASSERT(num_cores_total == num_cores_enabled); ++} ++ ++void mali_core_scaling_init(int num_pp_cores) ++{ ++ INIT_WORK(&wq_work, set_num_cores); ++ ++ num_cores_total = num_pp_cores; ++ num_cores_enabled = num_pp_cores; ++ ++ /* NOTE: Mali is not fully initialized at this point. */ ++} ++ ++void mali_core_scaling_sync(int num_cores) ++{ ++ num_cores_enabled = num_cores; ++} ++ ++void mali_core_scaling_term(void) ++{ ++ flush_scheduled_work(); ++} ++ ++#define PERCENT_OF(percent, max) ((int) ((percent)*(max)/100.0 + 0.5)) ++ ++void mali_core_scaling_update(struct mali_gpu_utilization_data *data) ++{ ++ /* ++ * This function implements a very trivial PP core scaling algorithm. ++ * ++ * It is _NOT_ of production quality. ++ * The only intention behind this algorithm is to exercise and test the ++ * core scaling functionality of the driver. ++ * It is _NOT_ tuned for neither power saving nor performance! ++ * ++ * Other metrics than PP utilization need to be considered as well ++ * in order to make a good core scaling algorithm. ++ */ ++ ++ MALI_DEBUG_PRINT(3, ("Utilization: (%3d, %3d, %3d), cores enabled: %d/%d\n", data->utilization_gpu, data->utilization_gp, data->utilization_pp, num_cores_enabled, num_cores_total)); ++ ++ /* NOTE: this function is normally called directly from the utilization callback which is in ++ * timer context. */ ++ ++ if ( PERCENT_OF(90, 256) < data->utilization_pp) { ++ enable_max_num_cores(); ++ } else if (PERCENT_OF(50, 256) < data->utilization_pp) { ++ enable_one_core(); ++ } else if (PERCENT_OF(40, 256) < data->utilization_pp) { ++ /* do nothing */ ++ } else if (PERCENT_OF( 0, 256) < data->utilization_pp) { ++ disable_one_core(); ++ } else { ++ /* do nothing */ ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.h +new file mode 100644 +index 0000000..193f43c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/platform/arm/arm_core_scaling.h +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file arm_core_scaling.h ++ * Example core scaling policy. ++ */ ++ ++#ifndef __ARM_CORE_SCALING_H__ ++#define __ARM_CORE_SCALING_H__ ++ ++struct mali_gpu_utilization_data; ++ ++/** ++ * Initialize core scaling policy. ++ * ++ * @note The core scaling policy will assume that all PP cores are on initially. ++ * ++ * @param num_pp_cores Total number of PP cores. ++ */ ++void mali_core_scaling_init(int num_pp_cores); ++ ++/** ++ * Terminate core scaling policy. ++ */ ++void mali_core_scaling_term(void); ++ ++/** ++ * Update core scaling policy with new utilization data. ++ * ++ * @param data Utilization data. ++ */ ++void mali_core_scaling_update(struct mali_gpu_utilization_data *data); ++ ++void mali_core_scaling_sync(int num_cores); ++ ++#endif /* __ARM_CORE_SCALING_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/readme.txt b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/readme.txt +new file mode 100644 +index 0000000..2609506 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/readme.txt +@@ -0,0 +1,24 @@ ++Building the Mali Device Driver for Linux ++----------------------------------------- ++ ++Build the Mali Device Driver for Linux by running the following make command: ++ ++KDIR= USING_UMP= BUILD= make ++ ++where ++ kdir_path: Path to your Linux Kernel directory ++ ump_option: 1 = Enable UMP support(*) ++ 0 = disable UMP support ++ build_option: debug = debug build of driver ++ release = release build of driver ++ ++(*) For newer Linux Kernels, the Module.symvers file for the UMP device driver ++ must be available. The UMP_SYMVERS_FILE variable in the Makefile should ++ point to this file. This file is generated when the UMP driver is built. ++ ++The result will be a mali.ko file, which can be loaded into the Linux kernel ++by using the insmod command. ++ ++The kernel needs to be provided with a platform_device struct for the Mali GPU ++device. See the mali_utgard.h header file for how to set up the Mali GPU ++resources. +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_200_regs.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_200_regs.h +new file mode 100644 +index 0000000..31c0d82 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_200_regs.h +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef _MALI200_REGS_H_ ++#define _MALI200_REGS_H_ ++ ++/** ++ * Enum for management register addresses. ++ */ ++enum mali200_mgmt_reg { ++ MALI200_REG_ADDR_MGMT_VERSION = 0x1000, ++ MALI200_REG_ADDR_MGMT_CURRENT_REND_LIST_ADDR = 0x1004, ++ MALI200_REG_ADDR_MGMT_STATUS = 0x1008, ++ MALI200_REG_ADDR_MGMT_CTRL_MGMT = 0x100c, ++ ++ MALI200_REG_ADDR_MGMT_INT_RAWSTAT = 0x1020, ++ MALI200_REG_ADDR_MGMT_INT_CLEAR = 0x1024, ++ MALI200_REG_ADDR_MGMT_INT_MASK = 0x1028, ++ MALI200_REG_ADDR_MGMT_INT_STATUS = 0x102c, ++ ++ MALI200_REG_ADDR_MGMT_WRITE_BOUNDARY_LOW = 0x1044, ++ ++ MALI200_REG_ADDR_MGMT_BUS_ERROR_STATUS = 0x1050, ++ ++ MALI200_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x1080, ++ MALI200_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x1084, ++ MALI200_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x108c, ++ ++ MALI200_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x10a0, ++ MALI200_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x10a4, ++ MALI200_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x10ac, ++ ++ MALI200_REG_ADDR_MGMT_PERFMON_CONTR = 0x10b0, ++ MALI200_REG_ADDR_MGMT_PERFMON_BASE = 0x10b4, ++ ++ MALI200_REG_SIZEOF_REGISTER_BANK = 0x10f0 ++ ++}; ++ ++#define MALI200_REG_VAL_PERF_CNT_ENABLE 1 ++ ++enum mali200_mgmt_ctrl_mgmt { ++ MALI200_REG_VAL_CTRL_MGMT_STOP_BUS = (1<<0), ++ MALI200_REG_VAL_CTRL_MGMT_FLUSH_CACHES = (1<<3), ++ MALI200_REG_VAL_CTRL_MGMT_FORCE_RESET = (1<<5), ++ MALI200_REG_VAL_CTRL_MGMT_START_RENDERING = (1<<6), ++ MALI400PP_REG_VAL_CTRL_MGMT_SOFT_RESET = (1<<7), /* Only valid for Mali-300 and later */ ++}; ++ ++enum mali200_mgmt_irq { ++ MALI200_REG_VAL_IRQ_END_OF_FRAME = (1<<0), ++ MALI200_REG_VAL_IRQ_END_OF_TILE = (1<<1), ++ MALI200_REG_VAL_IRQ_HANG = (1<<2), ++ MALI200_REG_VAL_IRQ_FORCE_HANG = (1<<3), ++ MALI200_REG_VAL_IRQ_BUS_ERROR = (1<<4), ++ MALI200_REG_VAL_IRQ_BUS_STOP = (1<<5), ++ MALI200_REG_VAL_IRQ_CNT_0_LIMIT = (1<<6), ++ MALI200_REG_VAL_IRQ_CNT_1_LIMIT = (1<<7), ++ MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR = (1<<8), ++ MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND = (1<<9), ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW = (1<<10), ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW = (1<<11), ++ MALI400PP_REG_VAL_IRQ_RESET_COMPLETED = (1<<12), ++}; ++ ++#define MALI200_REG_VAL_IRQ_MASK_ALL ((enum mali200_mgmt_irq) (\ ++ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ ++ MALI200_REG_VAL_IRQ_END_OF_TILE |\ ++ MALI200_REG_VAL_IRQ_HANG |\ ++ MALI200_REG_VAL_IRQ_FORCE_HANG |\ ++ MALI200_REG_VAL_IRQ_BUS_ERROR |\ ++ MALI200_REG_VAL_IRQ_BUS_STOP |\ ++ MALI200_REG_VAL_IRQ_CNT_0_LIMIT |\ ++ MALI200_REG_VAL_IRQ_CNT_1_LIMIT |\ ++ MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR |\ ++ MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND |\ ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW |\ ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW |\ ++ MALI400PP_REG_VAL_IRQ_RESET_COMPLETED)) ++ ++#define MALI200_REG_VAL_IRQ_MASK_USED ((enum mali200_mgmt_irq) (\ ++ MALI200_REG_VAL_IRQ_END_OF_FRAME |\ ++ MALI200_REG_VAL_IRQ_FORCE_HANG |\ ++ MALI200_REG_VAL_IRQ_BUS_ERROR |\ ++ MALI200_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR |\ ++ MALI400PP_REG_VAL_IRQ_INVALID_PLIST_COMMAND |\ ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW |\ ++ MALI400PP_REG_VAL_IRQ_CALL_STACK_OVERFLOW)) ++ ++#define MALI200_REG_VAL_IRQ_MASK_NONE ((enum mali200_mgmt_irq)(0)) ++ ++enum mali200_mgmt_status { ++ MALI200_REG_VAL_STATUS_RENDERING_ACTIVE = (1<<0), ++ MALI200_REG_VAL_STATUS_BUS_STOPPED = (1<<4), ++}; ++ ++enum mali200_render_unit { ++ MALI200_REG_ADDR_FRAME = 0x0000, ++ MALI200_REG_ADDR_RSW = 0x0004, ++ MALI200_REG_ADDR_STACK = 0x0030, ++ MALI200_REG_ADDR_STACK_SIZE = 0x0034, ++ MALI200_REG_ADDR_ORIGIN_OFFSET_X = 0x0040 ++}; ++ ++enum mali200_wb_unit { ++ MALI200_REG_ADDR_WB0 = 0x0100, ++ MALI200_REG_ADDR_WB1 = 0x0200, ++ MALI200_REG_ADDR_WB2 = 0x0300 ++}; ++ ++enum mali200_wb_unit_regs { ++ MALI200_REG_ADDR_WB_SOURCE_SELECT = 0x0000, ++ MALI200_REG_ADDR_WB_SOURCE_ADDR = 0x0004, ++}; ++ ++/* This should be in the top 16 bit of the version register of Mali PP */ ++#define MALI200_PP_PRODUCT_ID 0xC807 ++#define MALI300_PP_PRODUCT_ID 0xCE07 ++#define MALI400_PP_PRODUCT_ID 0xCD07 ++#define MALI450_PP_PRODUCT_ID 0xCF07 ++ ++ ++#endif /* _MALI200_REGS_H_ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_gp_regs.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_gp_regs.h +new file mode 100644 +index 0000000..04598e5 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/regs/mali_gp_regs.h +@@ -0,0 +1,172 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef _MALIGP2_CONROL_REGS_H_ ++#define _MALIGP2_CONROL_REGS_H_ ++ ++/** ++ * These are the different geometry processor control registers. ++ * Their usage is to control and monitor the operation of the ++ * Vertex Shader and the Polygon List Builder in the geometry processor. ++ * Addresses are in 32-bit word relative sizes. ++ * @see [P0081] "Geometry Processor Data Structures" for details ++ */ ++ ++typedef enum { ++ MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR = 0x00, ++ MALIGP2_REG_ADDR_MGMT_VSCL_END_ADDR = 0x04, ++ MALIGP2_REG_ADDR_MGMT_PLBUCL_START_ADDR = 0x08, ++ MALIGP2_REG_ADDR_MGMT_PLBUCL_END_ADDR = 0x0c, ++ MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_START_ADDR = 0x10, ++ MALIGP2_REG_ADDR_MGMT_PLBU_ALLOC_END_ADDR = 0x14, ++ MALIGP2_REG_ADDR_MGMT_CMD = 0x20, ++ MALIGP2_REG_ADDR_MGMT_INT_RAWSTAT = 0x24, ++ MALIGP2_REG_ADDR_MGMT_INT_CLEAR = 0x28, ++ MALIGP2_REG_ADDR_MGMT_INT_MASK = 0x2C, ++ MALIGP2_REG_ADDR_MGMT_INT_STAT = 0x30, ++ MALIGP2_REG_ADDR_MGMT_WRITE_BOUND_LOW = 0x34, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_ENABLE = 0x3C, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_ENABLE = 0x40, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC = 0x44, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_SRC = 0x48, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_VALUE = 0x4C, ++ MALIGP2_REG_ADDR_MGMT_PERF_CNT_1_VALUE = 0x50, ++ MALIGP2_REG_ADDR_MGMT_STATUS = 0x68, ++ MALIGP2_REG_ADDR_MGMT_VERSION = 0x6C, ++ MALIGP2_REG_ADDR_MGMT_VSCL_START_ADDR_READ = 0x80, ++ MALIGP2_REG_ADDR_MGMT_PLBCL_START_ADDR_READ = 0x84, ++ MALIGP2_CONTR_AXI_BUS_ERROR_STAT = 0x94, ++ MALIGP2_REGISTER_ADDRESS_SPACE_SIZE = 0x98, ++} maligp_reg_addr_mgmt_addr; ++ ++#define MALIGP2_REG_VAL_PERF_CNT_ENABLE 1 ++ ++/** ++ * Commands to geometry processor. ++ * @see MALIGP2_CTRL_REG_CMD ++ */ ++typedef enum { ++ MALIGP2_REG_VAL_CMD_START_VS = (1<< 0), ++ MALIGP2_REG_VAL_CMD_START_PLBU = (1<< 1), ++ MALIGP2_REG_VAL_CMD_UPDATE_PLBU_ALLOC = (1<< 4), ++ MALIGP2_REG_VAL_CMD_RESET = (1<< 5), ++ MALIGP2_REG_VAL_CMD_FORCE_HANG = (1<< 6), ++ MALIGP2_REG_VAL_CMD_STOP_BUS = (1<< 9), ++ MALI400GP_REG_VAL_CMD_SOFT_RESET = (1<<10), /* only valid for Mali-300 and later */ ++} mgp_contr_reg_val_cmd; ++ ++ ++/** @defgroup MALIGP2_IRQ ++ * Interrupt status of geometry processor. ++ * @see MALIGP2_CTRL_REG_INT_RAWSTAT, MALIGP2_REG_ADDR_MGMT_INT_CLEAR, ++ * MALIGP2_REG_ADDR_MGMT_INT_MASK, MALIGP2_REG_ADDR_MGMT_INT_STAT ++ * @{ ++ */ ++#define MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST (1 << 0) ++#define MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST (1 << 1) ++#define MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM (1 << 2) ++#define MALIGP2_REG_VAL_IRQ_VS_SEM_IRQ (1 << 3) ++#define MALIGP2_REG_VAL_IRQ_PLBU_SEM_IRQ (1 << 4) ++#define MALIGP2_REG_VAL_IRQ_HANG (1 << 5) ++#define MALIGP2_REG_VAL_IRQ_FORCE_HANG (1 << 6) ++#define MALIGP2_REG_VAL_IRQ_PERF_CNT_0_LIMIT (1 << 7) ++#define MALIGP2_REG_VAL_IRQ_PERF_CNT_1_LIMIT (1 << 8) ++#define MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR (1 << 9) ++#define MALIGP2_REG_VAL_IRQ_SYNC_ERROR (1 << 10) ++#define MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR (1 << 11) ++#define MALI400GP_REG_VAL_IRQ_AXI_BUS_STOPPED (1 << 12) ++#define MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD (1 << 13) ++#define MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD (1 << 14) ++#define MALI400GP_REG_VAL_IRQ_RESET_COMPLETED (1 << 19) ++#define MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW (1 << 20) ++#define MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW (1 << 21) ++#define MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS (1 << 22) ++ ++/* Mask defining all IRQs in Mali GP */ ++#define MALIGP2_REG_VAL_IRQ_MASK_ALL \ ++ (\ ++ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ ++ MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \ ++ MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \ ++ MALIGP2_REG_VAL_IRQ_VS_SEM_IRQ | \ ++ MALIGP2_REG_VAL_IRQ_PLBU_SEM_IRQ | \ ++ MALIGP2_REG_VAL_IRQ_HANG | \ ++ MALIGP2_REG_VAL_IRQ_FORCE_HANG | \ ++ MALIGP2_REG_VAL_IRQ_PERF_CNT_0_LIMIT | \ ++ MALIGP2_REG_VAL_IRQ_PERF_CNT_1_LIMIT | \ ++ MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \ ++ MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \ ++ MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR | \ ++ MALI400GP_REG_VAL_IRQ_AXI_BUS_STOPPED | \ ++ MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD | \ ++ MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD | \ ++ MALI400GP_REG_VAL_IRQ_RESET_COMPLETED | \ ++ MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW | \ ++ MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW | \ ++ MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) ++ ++/* Mask defining the IRQs in Mali GP which we use */ ++#define MALIGP2_REG_VAL_IRQ_MASK_USED \ ++ (\ ++ MALIGP2_REG_VAL_IRQ_VS_END_CMD_LST | \ ++ MALIGP2_REG_VAL_IRQ_PLBU_END_CMD_LST | \ ++ MALIGP2_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \ ++ MALIGP2_REG_VAL_IRQ_FORCE_HANG | \ ++ MALIGP2_REG_VAL_IRQ_WRITE_BOUND_ERR | \ ++ MALIGP2_REG_VAL_IRQ_SYNC_ERROR | \ ++ MALIGP2_REG_VAL_IRQ_AXI_BUS_ERROR | \ ++ MALI400GP_REG_VAL_IRQ_VS_INVALID_CMD | \ ++ MALI400GP_REG_VAL_IRQ_PLB_INVALID_CMD | \ ++ MALI400GP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW | \ ++ MALI400GP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW | \ ++ MALI400GP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) ++ ++/* Mask defining non IRQs on MaliGP2*/ ++#define MALIGP2_REG_VAL_IRQ_MASK_NONE 0 ++ ++/** }@ defgroup MALIGP2_IRQ*/ ++ ++/** @defgroup MALIGP2_STATUS ++ * The different Status values to the geometry processor. ++ * @see MALIGP2_CTRL_REG_STATUS ++ * @{ ++ */ ++#define MALIGP2_REG_VAL_STATUS_VS_ACTIVE 0x0002 ++#define MALIGP2_REG_VAL_STATUS_BUS_STOPPED 0x0004 ++#define MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE 0x0008 ++#define MALIGP2_REG_VAL_STATUS_BUS_ERROR 0x0040 ++#define MALIGP2_REG_VAL_STATUS_WRITE_BOUND_ERR 0x0100 ++/** }@ defgroup MALIGP2_STATUS*/ ++ ++#define MALIGP2_REG_VAL_STATUS_MASK_ACTIVE (\ ++ MALIGP2_REG_VAL_STATUS_VS_ACTIVE|\ ++ MALIGP2_REG_VAL_STATUS_PLBU_ACTIVE) ++ ++ ++#define MALIGP2_REG_VAL_STATUS_MASK_ERROR (\ ++ MALIGP2_REG_VAL_STATUS_BUS_ERROR |\ ++ MALIGP2_REG_VAL_STATUS_WRITE_BOUND_ERR ) ++ ++/* This should be in the top 16 bit of the version register of gp.*/ ++#define MALI200_GP_PRODUCT_ID 0xA07 ++#define MALI300_GP_PRODUCT_ID 0xC07 ++#define MALI400_GP_PRODUCT_ID 0xB07 ++#define MALI450_GP_PRODUCT_ID 0xD07 ++ ++/** ++ * The different sources for instrumented on the geometry processor. ++ * @see MALIGP2_REG_ADDR_MGMT_PERF_CNT_0_SRC ++ */ ++ ++enum MALIGP2_cont_reg_perf_cnt_src { ++ MALIGP2_REG_VAL_PERF_CNT1_SRC_NUMBER_OF_VERTICES_PROCESSED = 0x0a, ++}; ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.c +new file mode 100644 +index 0000000..86c8e31 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.c +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_timestamp.h" ++ ++/* This file is intentionally left empty, as all functions are inlined in mali_profiling_sampler.h */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.h +new file mode 100644 +index 0000000..175205b +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-arm11-cc/mali_timestamp.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_TIMESTAMP_H__ ++#define __MALI_TIMESTAMP_H__ ++ ++#include "mali_osk.h" ++ ++MALI_STATIC_INLINE _mali_osk_errcode_t _mali_timestamp_reset(void) ++{ ++ /* ++ * reset counters and overflow flags ++ */ ++ ++ u32 mask = (1 << 0) | /* enable all three counters */ ++ (0 << 1) | /* reset both Count Registers to 0x0 */ ++ (1 << 2) | /* reset the Cycle Counter Register to 0x0 */ ++ (0 << 3) | /* 1 = Cycle Counter Register counts every 64th processor clock cycle */ ++ (0 << 4) | /* Count Register 0 interrupt enable */ ++ (0 << 5) | /* Count Register 1 interrupt enable */ ++ (0 << 6) | /* Cycle Counter interrupt enable */ ++ (0 << 8) | /* Count Register 0 overflow flag (clear or write, flag on read) */ ++ (0 << 9) | /* Count Register 1 overflow flag (clear or write, flag on read) */ ++ (1 << 10); /* Cycle Counter Register overflow flag (clear or write, flag on read) */ ++ ++ __asm__ __volatile__ ("MCR p15, 0, %0, c15, c12, 0" : : "r" (mask) ); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++MALI_STATIC_INLINE u64 _mali_timestamp_get(void) ++{ ++ u32 result; ++ ++ /* this is for the clock cycles */ ++ __asm__ __volatile__ ("MRC p15, 0, %0, c15, c12, 1" : "=r" (result)); ++ ++ return (u64)result; ++} ++ ++#endif /* __MALI_TIMESTAMP_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.c +new file mode 100644 +index 0000000..86c8e31 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.c +@@ -0,0 +1,13 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_timestamp.h" ++ ++/* This file is intentionally left empty, as all functions are inlined in mali_profiling_sampler.h */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.h +new file mode 100644 +index 0000000..c3a3e1c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali/timestamp-default/mali_timestamp.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_TIMESTAMP_H__ ++#define __MALI_TIMESTAMP_H__ ++ ++#include "mali_osk.h" ++ ++MALI_STATIC_INLINE _mali_osk_errcode_t _mali_timestamp_reset(void) ++{ ++ return _MALI_OSK_ERR_OK; ++} ++ ++MALI_STATIC_INLINE u64 _mali_timestamp_get(void) ++{ ++ return _mali_osk_time_get_ns(); ++} ++ ++#endif /* __MALI_TIMESTAMP_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kbuild b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kbuild +new file mode 100644 +index 0000000..4f62b78 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kbuild +@@ -0,0 +1,94 @@ ++# ++# Copyright (C) 2010-2012 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++# Set default configuration to use, if Makefile didn't provide one. ++# Change this to use a different config.h ++CONFIG ?= os_memory_64m ++ ++# Validate selected config ++ifneq ($(shell [ -d $(src)/arch-$(CONFIG) ] && [ -f $(src)/arch-$(CONFIG)/config.h ] && echo "OK"), OK) ++$(warning Current directory is $(src)) ++$(error No configuration found for config $(CONFIG). Check that arch-$(CONFIG)/config.h exists) ++else ++# Link arch to the selected arch-config directory ++$(shell [ -L $(src)/arch ] && rm $(src)/arch) ++$(shell ln -sf arch-$(CONFIG) $(src)/arch) ++$(shell touch $(src)/arch/config.h) ++endif ++ ++UDD_FILE_PREFIX = ../mali/ ++ ++# Get subversion revision number, fall back to 0000 if no svn info is available ++SVN_INFO = (cd $(src); svn info 2>/dev/null) ++ ++ifneq ($(shell $(SVN_INFO) 2>/dev/null),) ++# SVN detected ++SVN_REV := $(shell $(SVN_INFO) | grep '^Revision: '| sed -e 's/^Revision: //' 2>/dev/null) ++DRIVER_REV := $(MALI_RELEASE_NAME)-r$(SVN_REV) ++CHANGE_DATE := $(shell $(SVN_INFO) | grep '^Last Changed Date: ' | cut -d: -f2- | cut -b2-) ++CHANGED_REVISION := $(shell $(SVN_INFO) | grep '^Last Changed Rev: ' | cut -d: -f2- | cut -b2-) ++REPO_URL := $(shell $(SVN_INFO) | grep '^URL: ' | cut -d: -f2- | cut -b2-) ++ ++else # SVN ++GIT_REV := $(shell cd $(src); git describe --always 2>/dev/null) ++ifneq ($(GIT_REV),) ++# Git detected ++DRIVER_REV := $(MALI_RELEASE_NAME)-$(GIT_REV) ++CHANGE_DATE := $(shell cd $(src); git log -1 --format="%ci") ++CHANGED_REVISION := $(GIT_REV) ++REPO_URL := $(shell cd $(src); git describe --all --always 2>/dev/null) ++ ++else # Git ++# No Git or SVN detected ++DRIVER_REV := $(MALI_RELEASE_NAME) ++CHANGE_DATE := $(MALI_RELEASE_NAME) ++CHANGED_REVISION := $(MALI_RELEASE_NAME) ++endif ++endif ++ ++ccflags-y += -DSVN_REV=$(SVN_REV) ++ccflags-y += -DSVN_REV_STRING=\"$(DRIVER_REV)\" ++ ++ccflags-y += -I$(src) -I$(src)/common -I$(src)/linux -I$(src)/../mali/common -I$(src)/../mali/linux -I$(src)/../../ump/include/ump ++ccflags-y += -DMALI_STATE_TRACKING=0 ++ccflags-y += -DMALI_ENABLE_CPU_CYCLES=0 ++ccflags-$(CONFIG_UMP_DEBUG) += -DDEBUG ++ ++# For customer releases the Linux Device Drivers will be provided as ARM proprietary and GPL releases: ++# The ARM proprietary product will only include the license/proprietary directory ++# The GPL product will only include the license/gpl directory ++ ++ifeq ($(wildcard $(src)/linux/license/gpl/*),) ++ccflags-y += -I$(src)/linux/license/proprietary -I$(src)/../mali/linux/license/proprietary ++else ++ccflags-y += -I$(src)/linux/license/gpl -I$(src)/../mali/linux/license/gpl ++endif ++ ++ump-y = common/ump_kernel_common.o \ ++ common/ump_kernel_descriptor_mapping.o \ ++ common/ump_kernel_api.o \ ++ common/ump_kernel_ref_drv.o \ ++ linux/ump_kernel_linux.o \ ++ linux/ump_kernel_memory_backend_os.o \ ++ linux/ump_kernel_memory_backend_dedicated.o \ ++ linux/ump_memory_backend.o \ ++ linux/ump_ukk_wrappers.o \ ++ linux/ump_ukk_ref_wrappers.o \ ++ linux/ump_osk_atomics.o \ ++ linux/ump_osk_low_level_mem.o \ ++ linux/ump_osk_misc.o \ ++ $(UDD_FILE_PREFIX)linux/mali_osk_atomics.o \ ++ $(UDD_FILE_PREFIX)linux/mali_osk_locks.o \ ++ $(UDD_FILE_PREFIX)linux/mali_osk_memory.o \ ++ $(UDD_FILE_PREFIX)linux/mali_osk_math.o \ ++ $(UDD_FILE_PREFIX)linux/mali_osk_misc.o ++ ++obj-$(CONFIG_UMP) := ump.o ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kconfig b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kconfig +new file mode 100644 +index 0000000..3ae316c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Kconfig +@@ -0,0 +1,16 @@ ++config UMP ++ tristate "UMP support" ++ depends on ARM ++ ---help--- ++ This enables support for the UMP memory allocation and sharing API. ++ ++ To compile this driver as a module, choose M here: the module will be ++ called ump. ++ ++config UMP_DEBUG ++ bool "Enable extra debug in UMP" ++ depends on UMP ++ default y ++ ---help--- ++ This enabled extra debug checks and messages in UMP. ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile +new file mode 100644 +index 0000000..e2aa8e5 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile +@@ -0,0 +1,67 @@ ++# ++# Copyright (C) 2010-2012 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++# For each arch check: CROSS_COMPILE , KDIR , CFLAGS += -DARCH ++ ++export ARCH ?= arm ++BUILD ?= debug ++ ++check_cc2 = \ ++ $(shell if $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; \ ++ then \ ++ echo "$(2)"; \ ++ else \ ++ echo "$(3)"; \ ++ fi ;) ++ ++# Check that required parameters are supplied. ++ifeq ($(CONFIG),) ++$(error "CONFIG must be specified.") ++endif ++ifeq ($(CPU)$(KDIR),) ++$(error "KDIR or CPU must be specified.") ++endif ++ ++# Get any user defined KDIR- or maybe even a hardcoded KDIR ++-include KDIR_CONFIGURATION ++ ++# Define host system directory ++KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build ++ ++ifeq ($(ARCH), arm) ++# when compiling for ARM we're cross compiling ++export CROSS_COMPILE ?= $(call check_cc2, arm-linux-gnueabi-gcc, arm-linux-gnueabi-, arm-none-linux-gnueabi-) ++endif ++ ++# look up KDIR based om CPU selection ++KDIR ?= $(KDIR-$(CPU)) ++ ++export CONFIG ++ ++export CONFIG_UMP := m ++ifeq ($(BUILD),debug) ++export CONFIG_UMP_DEBUG := y ++else ++export CONFIG_UMP_DEBUG := n ++endif ++ ++ifeq ($(KDIR),) ++$(error No KDIR found for platform $(CPU)) ++endif ++ ++all: ++ $(MAKE) -C $(KDIR) M=$(CURDIR) modules ++ ++kernelrelease: ++ $(MAKE) -C $(KDIR) kernelrelease ++ ++clean: ++ $(MAKE) -C $(KDIR) M=$(CURDIR) clean ++ $(MAKE) -C $(KDIR) M=$(CURDIR)/../mali clean +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile.common b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile.common +new file mode 100644 +index 0000000..e750ed7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/Makefile.common +@@ -0,0 +1,20 @@ ++# ++# Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++SRC = $(UMP_FILE_PREFIX)common/ump_kernel_common.c \ ++ $(UMP_FILE_PREFIX)common/ump_kernel_descriptor_mapping.c \ ++ $(UMP_FILE_PREFIX)common/ump_kernel_api.c \ ++ $(UMP_FILE_PREFIX)common/ump_kernel_ref_drv.c ++ ++# Get subversion revision number, fall back to 0000 if no svn info is available ++SVN_REV:=$(shell ((svnversion | grep -qv exported && echo -n 'Revision: ' && svnversion) || git svn info | sed -e 's/$$$$/M/' | grep '^Revision: ' || echo ${MALI_RELEASE_NAME}) 2>/dev/null | sed -e 's/^Revision: //') ++ ++EXTRA_CFLAGS += -DSVN_REV=$(SVN_REV) ++EXTRA_CFLAGS += -DSVN_REV_STRING=\"$(SVN_REV)\" +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-ca8-virtex820-m400-1/config.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-ca8-virtex820-m400-1/config.h +new file mode 100644 +index 0000000..97ebf3f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-ca8-virtex820-m400-1/config.h +@@ -0,0 +1,8 @@ ++#ifndef __ARCH_CONFIG_H__ ++#define __ARCH_CONFIG_H__ ++ ++#define ARCH_UMP_BACKEND_DEFAULT 1 ++#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0x5E000000 ++#define ARCH_UMP_MEMORY_SIZE_DEFAULT 512UL * 1024UL * 1024UL ++ ++#endif /* __ARCH_CONFIG_H__ */ +\ No newline at end of file +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-pb-virtex5/config.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-pb-virtex5/config.h +new file mode 100644 +index 0000000..850e28d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/arch-pb-virtex5/config.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __ARCH_CONFIG_H__ ++#define __ARCH_CONFIG_H__ ++ ++#define ARCH_UMP_BACKEND_DEFAULT 0 ++#define ARCH_UMP_MEMORY_ADDRESS_DEFAULT 0xE1000000 ++#define ARCH_UMP_MEMORY_SIZE_DEFAULT 16UL * 1024UL * 1024UL ++ ++#endif /* __ARCH_CONFIG_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_api.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_api.c +new file mode 100644 +index 0000000..000a912 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_api.c +@@ -0,0 +1,492 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++#include "ump_kernel_interface.h" ++#include "ump_kernel_common.h" ++ ++ ++ ++/* ---------------- UMP kernel space API functions follows ---------------- */ ++ ++ ++ ++UMP_KERNEL_API_EXPORT ump_secure_id ump_dd_secure_id_get(ump_dd_handle memh) ++{ ++ ump_dd_mem * mem = (ump_dd_mem *)memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ DBG_MSG(5, ("Returning secure ID. ID: %u\n", mem->secure_id)); ++ ++ return mem->secure_id; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id) ++{ ++ ump_dd_mem * mem; ++ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ++ DBG_MSG(5, ("Getting handle from secure ID. ID: %u\n", secure_id)); ++ if (0 != ump_descriptor_mapping_get(device.secure_id_map, (int)secure_id, (void**)&mem)) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(1, ("Secure ID not found. ID: %u\n", secure_id)); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ ++ ump_dd_reference_add(mem); ++ ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ return (ump_dd_handle)mem; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT unsigned long ump_dd_phys_block_count_get(ump_dd_handle memh) ++{ ++ ump_dd_mem * mem = (ump_dd_mem*) memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ return mem->nr_blocks; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle memh, ump_dd_physical_block * blocks, unsigned long num_blocks) ++{ ++ ump_dd_mem * mem = (ump_dd_mem *)memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ if (blocks == NULL) { ++ DBG_MSG(1, ("NULL parameter in ump_dd_phys_blocks_get()\n")); ++ return UMP_DD_INVALID; ++ } ++ ++ if (mem->nr_blocks != num_blocks) { ++ DBG_MSG(1, ("Specified number of blocks do not match actual number of blocks\n")); ++ return UMP_DD_INVALID; ++ } ++ ++ DBG_MSG(5, ("Returning physical block information. ID: %u\n", mem->secure_id)); ++ ++ _mali_osk_memcpy(blocks, mem->block_array, sizeof(ump_dd_physical_block) * mem->nr_blocks); ++ ++ return UMP_DD_SUCCESS; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle memh, unsigned long index, ump_dd_physical_block * block) ++{ ++ ump_dd_mem * mem = (ump_dd_mem *)memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ if (block == NULL) { ++ DBG_MSG(1, ("NULL parameter in ump_dd_phys_block_get()\n")); ++ return UMP_DD_INVALID; ++ } ++ ++ if (index >= mem->nr_blocks) { ++ DBG_MSG(5, ("Invalid index specified in ump_dd_phys_block_get()\n")); ++ return UMP_DD_INVALID; ++ } ++ ++ DBG_MSG(5, ("Returning physical block information. ID: %u, index: %lu\n", mem->secure_id, index)); ++ ++ *block = mem->block_array[index]; ++ ++ return UMP_DD_SUCCESS; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT unsigned long ump_dd_size_get(ump_dd_handle memh) ++{ ++ ump_dd_mem * mem = (ump_dd_mem*)memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ DBG_MSG(5, ("Returning size. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes)); ++ ++ return mem->size_bytes; ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle memh) ++{ ++ ump_dd_mem * mem = (ump_dd_mem*)memh; ++ int new_ref; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ new_ref = _ump_osk_atomic_inc_and_read(&mem->ref_count); ++ ++ DBG_MSG(5, ("Memory reference incremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); ++} ++ ++ ++ ++UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle memh) ++{ ++ int new_ref; ++ ump_dd_mem * mem = (ump_dd_mem*)memh; ++ ++ DEBUG_ASSERT_POINTER(mem); ++ ++ /* We must hold this mutex while doing the atomic_dec_and_read, to protect ++ that elements in the ump_descriptor_mapping table is always valid. If they ++ are not, userspace may accidently map in this secure_ids right before its freed ++ giving a mapped backdoor into unallocated memory.*/ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ++ new_ref = _ump_osk_atomic_dec_and_read(&mem->ref_count); ++ ++ DBG_MSG(5, ("Memory reference decremented. ID: %u, new value: %d\n", mem->secure_id, new_ref)); ++ ++ if (0 == new_ref) { ++ DBG_MSG(3, ("Final release of memory. ID: %u\n", mem->secure_id)); ++ ++ ump_descriptor_mapping_free(device.secure_id_map, (int)mem->secure_id); ++ ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ mem->release_func(mem->ctx, mem); ++ _mali_osk_free(mem); ++ } else { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ } ++} ++ ++ ++ ++/* --------------- Handling of user space requests follows --------------- */ ++ ++ ++_mali_osk_errcode_t _ump_uku_get_api_version( _ump_uk_api_version_s *args ) ++{ ++ ump_session_data * session_data; ++ ++ DEBUG_ASSERT_POINTER( args ); ++ DEBUG_ASSERT_POINTER( args->ctx ); ++ ++ session_data = (ump_session_data *)args->ctx; ++ ++ /* check compatability */ ++ if (args->version == UMP_IOCTL_API_VERSION) { ++ DBG_MSG(3, ("API version set to newest %d (compatible)\n", GET_VERSION(args->version))); ++ args->compatible = 1; ++ session_data->api_version = args->version; ++ } else if (args->version == MAKE_VERSION_ID(1)) { ++ DBG_MSG(2, ("API version set to depricated: %d (compatible)\n", GET_VERSION(args->version))); ++ args->compatible = 1; ++ session_data->api_version = args->version; ++ } else { ++ DBG_MSG(2, ("API version set to %d (incompatible with client version %d)\n", GET_VERSION(UMP_IOCTL_API_VERSION), GET_VERSION(args->version))); ++ args->compatible = 0; ++ args->version = UMP_IOCTL_API_VERSION; /* report our version */ ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++ ++_mali_osk_errcode_t _ump_ukk_release( _ump_uk_release_s *release_info ) ++{ ++ ump_session_memory_list_element * session_memory_element; ++ ump_session_memory_list_element * tmp; ++ ump_session_data * session_data; ++ _mali_osk_errcode_t ret = _MALI_OSK_ERR_INVALID_FUNC; ++ int secure_id; ++ ++ DEBUG_ASSERT_POINTER( release_info ); ++ DEBUG_ASSERT_POINTER( release_info->ctx ); ++ ++ /* Retreive the session data */ ++ session_data = (ump_session_data*)release_info->ctx; ++ ++ /* If there are many items in the memory session list we ++ * could be de-referencing this pointer a lot so keep a local copy ++ */ ++ secure_id = release_info->secure_id; ++ ++ DBG_MSG(4, ("Releasing memory with IOCTL, ID: %u\n", secure_id)); ++ ++ /* Iterate through the memory list looking for the requested secure ID */ ++ _mali_osk_mutex_wait(session_data->lock); ++ _MALI_OSK_LIST_FOREACHENTRY(session_memory_element, tmp, &session_data->list_head_session_memory_list, ump_session_memory_list_element, list) { ++ if ( session_memory_element->mem->secure_id == secure_id) { ++ ump_dd_mem *release_mem; ++ ++ release_mem = session_memory_element->mem; ++ _mali_osk_list_del(&session_memory_element->list); ++ ump_dd_reference_release(release_mem); ++ _mali_osk_free(session_memory_element); ++ ++ ret = _MALI_OSK_ERR_OK; ++ break; ++ } ++ } ++ ++ _mali_osk_mutex_signal(session_data->lock); ++ DBG_MSG_IF(1, _MALI_OSK_ERR_OK != ret, ("UMP memory with ID %u does not belong to this session.\n", secure_id)); ++ ++ DBG_MSG(4, ("_ump_ukk_release() returning 0x%x\n", ret)); ++ return ret; ++} ++ ++_mali_osk_errcode_t _ump_ukk_size_get( _ump_uk_size_get_s *user_interaction ) ++{ ++ ump_dd_mem * mem; ++ _mali_osk_errcode_t ret = _MALI_OSK_ERR_FAULT; ++ ++ DEBUG_ASSERT_POINTER( user_interaction ); ++ ++ /* We lock the mappings so things don't get removed while we are looking for the memory */ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ if (0 == ump_descriptor_mapping_get(device.secure_id_map, (int)user_interaction->secure_id, (void**)&mem)) { ++ user_interaction->size = mem->size_bytes; ++ DBG_MSG(4, ("Returning size. ID: %u, size: %lu ", (ump_secure_id)user_interaction->secure_id, (unsigned long)user_interaction->size)); ++ ret = _MALI_OSK_ERR_OK; ++ } else { ++ user_interaction->size = 0; ++ DBG_MSG(1, ("Failed to look up mapping in ump_ioctl_size_get(). ID: %u\n", (ump_secure_id)user_interaction->secure_id)); ++ } ++ ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ return ret; ++} ++ ++ ++ ++void _ump_ukk_msync( _ump_uk_msync_s *args ) ++{ ++ ump_dd_mem * mem = NULL; ++ void *virtual = NULL; ++ u32 size = 0; ++ u32 offset = 0; ++ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); ++ ++ if (NULL == mem) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_msync(). ID: %u\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ /* Ensure the memory doesn't dissapear when we are flushing it. */ ++ ump_dd_reference_add(mem); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ /* Returns the cache settings back to Userspace */ ++ args->is_cached=mem->is_cached; ++ ++ /* If this flag is the only one set, we should not do the actual flush, only the readout */ ++ if ( _UMP_UK_MSYNC_READOUT_CACHE_ENABLED==args->op ) { ++ DBG_MSG(3, ("_ump_ukk_msync READOUT ID: %u Enabled: %d\n", (ump_secure_id)args->secure_id, mem->is_cached)); ++ goto msync_release_and_return; ++ } ++ ++ /* Nothing to do if the memory is not caches */ ++ if ( 0==mem->is_cached ) { ++ DBG_MSG(3, ("_ump_ukk_msync IGNORING ID: %u Enabled: %d OP: %d\n", (ump_secure_id)args->secure_id, mem->is_cached, args->op)); ++ goto msync_release_and_return; ++ } ++ DBG_MSG(3, ("UMP[%02u] _ump_ukk_msync Flush OP: %d Address: 0x%08x Mapping: 0x%08x\n", ++ (ump_secure_id)args->secure_id, args->op, args->address, args->mapping)); ++ ++ if ( args->address ) { ++ virtual = (void *)((u32)args->address); ++ offset = (u32)((args->address) - (args->mapping)); ++ } else { ++ /* Flush entire mapping when no address is specified. */ ++ virtual = args->mapping; ++ } ++ if ( args->size ) { ++ size = args->size; ++ } else { ++ /* Flush entire mapping when no size is specified. */ ++ size = mem->size_bytes - offset; ++ } ++ ++ if ( (offset + size) > mem->size_bytes ) { ++ DBG_MSG(1, ("Trying to flush more than the entire UMP allocation: offset: %u + size: %u > %u\n", offset, size, mem->size_bytes)); ++ goto msync_release_and_return; ++ } ++ ++ /* The actual cache flush - Implemented for each OS*/ ++ _ump_osk_msync( mem, virtual, offset, size, args->op, NULL); ++ ++msync_release_and_return: ++ ump_dd_reference_release(mem); ++ return; ++} ++ ++void _ump_ukk_cache_operations_control(_ump_uk_cache_operations_control_s* args) ++{ ++ ump_session_data * session_data; ++ ump_uk_cache_op_control op; ++ ++ DEBUG_ASSERT_POINTER( args ); ++ DEBUG_ASSERT_POINTER( args->ctx ); ++ ++ op = args->op; ++ session_data = (ump_session_data *)args->ctx; ++ ++ _mali_osk_mutex_wait(session_data->lock); ++ if ( op== _UMP_UK_CACHE_OP_START ) { ++ session_data->cache_operations_ongoing++; ++ DBG_MSG(4, ("Cache ops start\n" )); ++ if ( session_data->cache_operations_ongoing != 1 ) { ++ DBG_MSG(2, ("UMP: Number of simultanious cache control ops: %d\n", session_data->cache_operations_ongoing) ); ++ } ++ } else if ( op== _UMP_UK_CACHE_OP_FINISH ) { ++ DBG_MSG(4, ("Cache ops finish\n")); ++ session_data->cache_operations_ongoing--; ++#if 0 ++ if ( session_data->has_pending_level1_cache_flush) { ++ /* This function will set has_pending_level1_cache_flush=0 */ ++ _ump_osk_msync( NULL, NULL, 0, 0, _UMP_UK_MSYNC_FLUSH_L1, session_data); ++ } ++#endif ++ ++ /* to be on the safe side: always flush l1 cache when cache operations are done */ ++ _ump_osk_msync( NULL, NULL, 0, 0, _UMP_UK_MSYNC_FLUSH_L1, session_data); ++ DBG_MSG(4, ("Cache ops finish end\n" )); ++ } else { ++ DBG_MSG(1, ("Illegal call to %s at line %d\n", __FUNCTION__, __LINE__)); ++ } ++ _mali_osk_mutex_signal(session_data->lock); ++ ++} ++ ++void _ump_ukk_switch_hw_usage(_ump_uk_switch_hw_usage_s *args ) ++{ ++ ump_dd_mem * mem = NULL; ++ ump_uk_user old_user; ++ ump_uk_msync_op cache_op = _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE; ++ ump_session_data *session_data; ++ ++ DEBUG_ASSERT_POINTER( args ); ++ DEBUG_ASSERT_POINTER( args->ctx ); ++ ++ session_data = (ump_session_data *)args->ctx; ++ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); ++ ++ if (NULL == mem) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_switch_hw_usage(). ID: %u\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ ++ old_user = mem->hw_device; ++ mem->hw_device = args->new_user; ++ ++ DBG_MSG(3, ("UMP[%02u] Switch usage Start New: %s Prev: %s.\n", (ump_secure_id)args->secure_id, args->new_user?"MALI":"CPU",old_user?"MALI":"CPU")); ++ ++ if ( ! mem->is_cached ) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(3, ("UMP[%02u] Changing owner of uncached memory. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ ++ if ( old_user == args->new_user) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(4, ("UMP[%02u] Setting the new_user equal to previous for. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ if ( ++ /* Previous AND new is both different from CPU */ ++ (old_user != _UMP_UK_USED_BY_CPU) && (args->new_user != _UMP_UK_USED_BY_CPU ) ++ ) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(4, ("UMP[%02u] Previous and new user is not CPU. Cache flushing not needed.\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ ++ if ( (old_user != _UMP_UK_USED_BY_CPU ) && (args->new_user==_UMP_UK_USED_BY_CPU) ) { ++ cache_op =_UMP_UK_MSYNC_INVALIDATE; ++ DBG_MSG(4, ("UMP[%02u] Cache invalidation needed\n", (ump_secure_id)args->secure_id)); ++#ifdef UMP_SKIP_INVALIDATION ++#error ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(4, ("UMP[%02u] Performing Cache invalidation SKIPPED\n", (ump_secure_id)args->secure_id)); ++ return; ++#endif ++ } ++ /* Ensure the memory doesn't dissapear when we are flushing it. */ ++ ump_dd_reference_add(mem); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ /* Take lock to protect: session->cache_operations_ongoing and session->has_pending_level1_cache_flush */ ++ _mali_osk_mutex_wait(session_data->lock); ++ /* Actual cache flush */ ++ _ump_osk_msync( mem, NULL, 0, mem->size_bytes, cache_op, session_data); ++ _mali_osk_mutex_signal(session_data->lock); ++ ++ ump_dd_reference_release(mem); ++ DBG_MSG(4, ("UMP[%02u] Switch usage Finish\n", (ump_secure_id)args->secure_id)); ++ return; ++} ++ ++void _ump_ukk_lock(_ump_uk_lock_s *args ) ++{ ++ ump_dd_mem * mem = NULL; ++ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); ++ ++ if (NULL == mem) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(1, ("UMP[%02u] Failed to look up mapping in _ump_ukk_lock(). ID: %u\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ ump_dd_reference_add(mem); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ DBG_MSG(1, ("UMP[%02u] Lock. New lock flag: %d. Old Lock flag:\n", (u32)args->secure_id, (u32)args->lock_usage, (u32) mem->lock_usage )); ++ ++ mem->lock_usage = (ump_lock_usage) args->lock_usage; ++ ++ ump_dd_reference_release(mem); ++} ++ ++void _ump_ukk_unlock(_ump_uk_unlock_s *args ) ++{ ++ ump_dd_mem * mem = NULL; ++ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ ump_descriptor_mapping_get(device.secure_id_map, (int)args->secure_id, (void**)&mem); ++ ++ if (NULL == mem) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(1, ("Failed to look up mapping in _ump_ukk_unlock(). ID: %u\n", (ump_secure_id)args->secure_id)); ++ return; ++ } ++ ump_dd_reference_add(mem); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ DBG_MSG(1, ("UMP[%02u] Unlocking. Old Lock flag:\n", (u32)args->secure_id, (u32) mem->lock_usage )); ++ ++ mem->lock_usage = (ump_lock_usage) UMP_NOT_LOCKED; ++ ++ ump_dd_reference_release(mem); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.c +new file mode 100644 +index 0000000..e207eea +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.c +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_osk_bitops.h" ++#include "mali_osk_list.h" ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++#include "ump_ukk.h" ++#include "ump_kernel_common.h" ++#include "ump_kernel_descriptor_mapping.h" ++#include "ump_kernel_memory_backend.h" ++ ++ ++ ++/** ++ * Define the initial and maximum size of number of secure_ids on the system ++ */ ++#define UMP_SECURE_ID_TABLE_ENTRIES_INITIAL (128 ) ++#define UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM (4096 ) ++ ++ ++/** ++ * Define the initial and maximum size of the ump_session_data::cookies_map, ++ * which is a \ref ump_descriptor_mapping. This limits how many secure_ids ++ * may be mapped into a particular process using _ump_ukk_map_mem(). ++ */ ++ ++#define UMP_COOKIES_PER_SESSION_INITIAL (UMP_SECURE_ID_TABLE_ENTRIES_INITIAL ) ++#define UMP_COOKIES_PER_SESSION_MAXIMUM (UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM) ++ ++struct ump_dev device; ++ ++_mali_osk_errcode_t ump_kernel_constructor(void) ++{ ++ _mali_osk_errcode_t err; ++ ++ /* Perform OS Specific initialization */ ++ err = _ump_osk_init(); ++ if( _MALI_OSK_ERR_OK != err ) { ++ MSG_ERR(("Failed to initiaze the UMP Device Driver")); ++ return err; ++ } ++ ++ /* Init the global device */ ++ _mali_osk_memset(&device, 0, sizeof(device) ); ++ ++ /* Create the descriptor map, which will be used for mapping secure ID to ump_dd_mem structs */ ++ device.secure_id_map_lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_UNORDERED, 0); ++ if (NULL == device.secure_id_map_lock) { ++ MSG_ERR(("Failed to create OSK lock for secure id lookup table\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ device.secure_id_map = ump_descriptor_mapping_create(UMP_SECURE_ID_TABLE_ENTRIES_INITIAL, UMP_SECURE_ID_TABLE_ENTRIES_MAXIMUM); ++ if (NULL == device.secure_id_map) { ++ _mali_osk_mutex_term(device.secure_id_map_lock); ++ MSG_ERR(("Failed to create secure id lookup table\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ /* Init memory backend */ ++ device.backend = ump_memory_backend_create(); ++ if (NULL == device.backend) { ++ MSG_ERR(("Failed to create memory backend\n")); ++ _mali_osk_mutex_term(device.secure_id_map_lock); ++ ump_descriptor_mapping_destroy(device.secure_id_map); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void ump_kernel_destructor(void) ++{ ++ DEBUG_ASSERT_POINTER(device.secure_id_map); ++ DEBUG_ASSERT_POINTER(device.secure_id_map_lock); ++ ++ _mali_osk_mutex_term(device.secure_id_map_lock); ++ device.secure_id_map_lock = NULL; ++ ++ ump_descriptor_mapping_destroy(device.secure_id_map); ++ device.secure_id_map = NULL; ++ ++ device.backend->shutdown(device.backend); ++ device.backend = NULL; ++ ++ ump_memory_backend_destroy(); ++ ++ _ump_osk_term(); ++} ++ ++/** Creates a new UMP session ++ */ ++_mali_osk_errcode_t _ump_ukk_open( void** context ) ++{ ++ struct ump_session_data * session_data; ++ ++ /* allocated struct to track this session */ ++ session_data = (struct ump_session_data *)_mali_osk_malloc(sizeof(struct ump_session_data)); ++ if (NULL == session_data) { ++ MSG_ERR(("Failed to allocate ump_session_data in ump_file_open()\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ session_data->lock = _mali_osk_mutex_init(_MALI_OSK_LOCKFLAG_UNORDERED, 0); ++ if( NULL == session_data->lock ) { ++ MSG_ERR(("Failed to initialize lock for ump_session_data in ump_file_open()\n")); ++ _mali_osk_free(session_data); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ session_data->cookies_map = ump_descriptor_mapping_create( UMP_COOKIES_PER_SESSION_INITIAL, UMP_COOKIES_PER_SESSION_MAXIMUM ); ++ ++ if ( NULL == session_data->cookies_map ) { ++ MSG_ERR(("Failed to create descriptor mapping for _ump_ukk_map_mem cookies\n")); ++ ++ _mali_osk_mutex_term(session_data->lock); ++ _mali_osk_free( session_data ); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_list); ++ ++ _MALI_OSK_INIT_LIST_HEAD(&session_data->list_head_session_memory_mappings_list); ++ ++ /* Since initial version of the UMP interface did not use the API_VERSION ioctl we have to assume ++ that it is this version, and not the "latest" one: UMP_IOCTL_API_VERSION ++ Current and later API versions would do an additional call to this IOCTL and update this variable ++ to the correct one.*/ ++ session_data->api_version = MAKE_VERSION_ID(1); ++ ++ *context = (void*)session_data; ++ ++ session_data->cache_operations_ongoing = 0 ; ++ session_data->has_pending_level1_cache_flush = 0; ++ ++ DBG_MSG(2, ("New session opened\n")); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _ump_ukk_close( void** context ) ++{ ++ struct ump_session_data * session_data; ++ ump_session_memory_list_element * item; ++ ump_session_memory_list_element * tmp; ++ ++ session_data = (struct ump_session_data *)*context; ++ if (NULL == session_data) { ++ MSG_ERR(("Session data is NULL in _ump_ukk_close()\n")); ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ /* Unmap any descriptors mapped in. */ ++ if (0 == _mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list)) { ++ ump_memory_allocation *descriptor; ++ ump_memory_allocation *temp; ++ ++ DBG_MSG(1, ("Memory mappings found on session usage list during session termination\n")); ++ ++ /* use the 'safe' list iterator, since freeing removes the active block from the list we're iterating */ ++ _MALI_OSK_LIST_FOREACHENTRY(descriptor, temp, &session_data->list_head_session_memory_mappings_list, ump_memory_allocation, list) { ++ _ump_uk_unmap_mem_s unmap_args; ++ DBG_MSG(4, ("Freeing block with phys address 0x%x size 0x%x mapped in user space at 0x%x\n", ++ descriptor->phys_addr, descriptor->size, descriptor->mapping)); ++ unmap_args.ctx = (void*)session_data; ++ unmap_args.mapping = descriptor->mapping; ++ unmap_args.size = descriptor->size; ++ unmap_args._ukk_private = NULL; /* NOTE: unused */ ++ unmap_args.cookie = descriptor->cookie; ++ ++ /* NOTE: This modifies the list_head_session_memory_mappings_list */ ++ _ump_ukk_unmap_mem( &unmap_args ); ++ } ++ } ++ ++ /* ASSERT that we really did free everything, because _ump_ukk_unmap_mem() ++ * can fail silently. */ ++ DEBUG_ASSERT( _mali_osk_list_empty(&session_data->list_head_session_memory_mappings_list) ); ++ ++ _MALI_OSK_LIST_FOREACHENTRY(item, tmp, &session_data->list_head_session_memory_list, ump_session_memory_list_element, list) { ++ _mali_osk_list_del(&item->list); ++ DBG_MSG(2, ("Releasing UMP memory %u as part of file close\n", item->mem->secure_id)); ++ ump_dd_reference_release(item->mem); ++ _mali_osk_free(item); ++ } ++ ++ ump_descriptor_mapping_destroy( session_data->cookies_map ); ++ ++ _mali_osk_mutex_term(session_data->lock); ++ _mali_osk_free(session_data); ++ ++ DBG_MSG(2, ("Session closed\n")); ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _ump_ukk_map_mem( _ump_uk_map_mem_s *args ) ++{ ++ struct ump_session_data * session_data; ++ ump_memory_allocation * descriptor; /* Describes current mapping of memory */ ++ _mali_osk_errcode_t err; ++ unsigned long offset = 0; ++ unsigned long left; ++ ump_dd_handle handle; /* The real UMP handle for this memory. Its real datatype is ump_dd_mem* */ ++ ump_dd_mem * mem; /* The real UMP memory. It is equal to the handle, but with exposed struct */ ++ u32 block; ++ int map_id; ++ ++ session_data = (ump_session_data *)args->ctx; ++ if( NULL == session_data ) { ++ MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n")); ++ return _MALI_OSK_ERR_INVALID_ARGS; ++ } ++ ++ descriptor = (ump_memory_allocation*) _mali_osk_calloc( 1, sizeof(ump_memory_allocation)); ++ if (NULL == descriptor) { ++ MSG_ERR(("ump_ukk_map_mem: descriptor allocation failed\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ handle = ump_dd_handle_create_from_secure_id(args->secure_id); ++ if ( UMP_DD_HANDLE_INVALID == handle) { ++ _mali_osk_free(descriptor); ++ DBG_MSG(1, ("Trying to map unknown secure ID %u\n", args->secure_id)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ mem = (ump_dd_mem*)handle; ++ DEBUG_ASSERT(mem); ++ if (mem->size_bytes != args->size) { ++ _mali_osk_free(descriptor); ++ ump_dd_reference_release(handle); ++ DBG_MSG(1, ("Trying to map too much or little. ID: %u, virtual size=%lu, UMP size: %lu\n", args->secure_id, args->size, mem->size_bytes)); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ map_id = ump_descriptor_mapping_allocate_mapping( session_data->cookies_map, (void*) descriptor ); ++ ++ if (map_id < 0) { ++ _mali_osk_free(descriptor); ++ ump_dd_reference_release(handle); ++ DBG_MSG(1, ("ump_ukk_map_mem: unable to allocate a descriptor_mapping for return cookie\n")); ++ ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ descriptor->size = args->size; ++ descriptor->handle = handle; ++ descriptor->phys_addr = args->phys_addr; ++ descriptor->process_mapping_info = args->_ukk_private; ++ descriptor->ump_session = session_data; ++ descriptor->cookie = (u32)map_id; ++ ++ if ( mem->is_cached ) { ++ descriptor->is_cached = 1; ++ args->is_cached = 1; ++ DBG_MSG(3, ("Mapping UMP secure_id: %d as cached.\n", args->secure_id)); ++ } else { ++ descriptor->is_cached = 0; ++ args->is_cached = 0; ++ DBG_MSG(3, ("Mapping UMP secure_id: %d as Uncached.\n", args->secure_id)); ++ } ++ ++ _mali_osk_list_init( &descriptor->list ); ++ ++ err = _ump_osk_mem_mapregion_init( descriptor ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ DBG_MSG(1, ("Failed to initialize memory mapping in _ump_ukk_map_mem(). ID: %u\n", args->secure_id)); ++ ump_descriptor_mapping_free( session_data->cookies_map, map_id ); ++ _mali_osk_free(descriptor); ++ ump_dd_reference_release(mem); ++ return err; ++ } ++ ++ DBG_MSG(4, ("Mapping virtual to physical memory: ID: %u, size:%lu, first physical addr: 0x%08lx, number of regions: %lu\n", ++ mem->secure_id, ++ mem->size_bytes, ++ ((NULL != mem->block_array) ? mem->block_array->addr : 0), ++ mem->nr_blocks)); ++ ++ left = descriptor->size; ++ /* loop over all blocks and map them in */ ++ for (block = 0; block < mem->nr_blocks; block++) { ++ unsigned long size_to_map; ++ ++ if (left > mem->block_array[block].size) { ++ size_to_map = mem->block_array[block].size; ++ } else { ++ size_to_map = left; ++ } ++ ++ if (_MALI_OSK_ERR_OK != _ump_osk_mem_mapregion_map(descriptor, offset, (u32 *)&(mem->block_array[block].addr), size_to_map ) ) { ++ DBG_MSG(1, ("WARNING: _ump_ukk_map_mem failed to map memory into userspace\n")); ++ ump_descriptor_mapping_free( session_data->cookies_map, map_id ); ++ ump_dd_reference_release(mem); ++ _ump_osk_mem_mapregion_term( descriptor ); ++ _mali_osk_free(descriptor); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ left -= size_to_map; ++ offset += size_to_map; ++ } ++ ++ /* Add to the ump_memory_allocation tracking list */ ++ _mali_osk_mutex_wait(session_data->lock); ++ _mali_osk_list_add( &descriptor->list, &session_data->list_head_session_memory_mappings_list ); ++ _mali_osk_mutex_signal(session_data->lock); ++ ++ args->mapping = descriptor->mapping; ++ args->cookie = descriptor->cookie; ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s *args ) ++{ ++ struct ump_session_data * session_data; ++ ump_memory_allocation * descriptor; ++ ump_dd_handle handle; ++ ++ session_data = (ump_session_data *)args->ctx; ++ ++ if( NULL == session_data ) { ++ MSG_ERR(("Session data is NULL in _ump_ukk_map_mem()\n")); ++ return; ++ } ++ ++ if (0 != ump_descriptor_mapping_get( session_data->cookies_map, (int)args->cookie, (void**)&descriptor) ) { ++ MSG_ERR(("_ump_ukk_map_mem: cookie 0x%X not found for this session\n", args->cookie )); ++ return; ++ } ++ ++ DEBUG_ASSERT_POINTER(descriptor); ++ ++ handle = descriptor->handle; ++ if ( UMP_DD_HANDLE_INVALID == handle) { ++ DBG_MSG(1, ("WARNING: Trying to unmap unknown handle: UNKNOWN\n")); ++ return; ++ } ++ ++ /* Remove the ump_memory_allocation from the list of tracked mappings */ ++ _mali_osk_mutex_wait(session_data->lock); ++ _mali_osk_list_del( &descriptor->list ); ++ _mali_osk_mutex_signal(session_data->lock); ++ ++ ump_descriptor_mapping_free( session_data->cookies_map, (int)args->cookie ); ++ ++ ump_dd_reference_release(handle); ++ ++ _ump_osk_mem_mapregion_term( descriptor ); ++ _mali_osk_free(descriptor); ++} ++ ++u32 _ump_ukk_report_memory_usage( void ) ++{ ++ if(device.backend->stat) ++ return device.backend->stat(device.backend); ++ else ++ return 0; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.h +new file mode 100644 +index 0000000..fa4639f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_common.h +@@ -0,0 +1,125 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __UMP_KERNEL_COMMON_H__ ++#define __UMP_KERNEL_COMMON_H__ ++ ++#include "ump_kernel_types.h" ++#include "ump_kernel_interface.h" ++#include "ump_kernel_descriptor_mapping.h" ++#include "ump_kernel_memory_backend.h" ++ ++ ++#ifdef DEBUG ++extern int ump_debug_level; ++#define UMP_DEBUG_PRINT(args) _mali_osk_dbgmsg args ++#define UMP_DEBUG_CODE(args) args ++#define DBG_MSG(level,args) do { /* args should be in brackets */ \ ++ ((level) <= ump_debug_level)?\ ++ UMP_DEBUG_PRINT(("UMP<" #level ">: ")), \ ++ UMP_DEBUG_PRINT(args):0; \ ++ } while (0) ++ ++#define DBG_MSG_IF(level,condition,args) /* args should be in brackets */ \ ++ if((condition)&&((level) <= ump_debug_level)) {\ ++ UMP_DEBUG_PRINT(("UMP<" #level ">: ")); \ ++ UMP_DEBUG_PRINT(args); \ ++ } ++ ++#define DBG_MSG_ELSE(level,args) /* args should be in brackets */ \ ++ else if((level) <= ump_debug_level) { \ ++ UMP_DEBUG_PRINT(("UMP<" #level ">: ")); \ ++ UMP_DEBUG_PRINT(args); \ ++ } ++ ++#define DEBUG_ASSERT_POINTER(pointer) do {if( (pointer)== NULL) MSG_ERR(("NULL pointer " #pointer)); } while(0) ++#define DEBUG_ASSERT(condition) do {if(!(condition)) MSG_ERR(("ASSERT failed: " #condition)); } while(0) ++#else /* DEBUG */ ++#define UMP_DEBUG_PRINT(args) do {} while(0) ++#define UMP_DEBUG_CODE(args) ++#define DBG_MSG(level,args) do {} while(0) ++#define DBG_MSG_IF(level,condition,args) do {} while(0) ++#define DBG_MSG_ELSE(level,args) do {} while(0) ++#define DEBUG_ASSERT(condition) do {} while(0) ++#define DEBUG_ASSERT_POINTER(pointer) do {} while(0) ++#endif /* DEBUG */ ++ ++#define MSG_ERR(args) do{ /* args should be in brackets */ \ ++ _mali_osk_dbgmsg("UMP: ERR: %s\n" ,__FILE__); \ ++ _mali_osk_dbgmsg( " %s()%4d\n", __FUNCTION__, __LINE__) ; \ ++ _mali_osk_dbgmsg args ; \ ++ _mali_osk_dbgmsg("\n"); \ ++ } while(0) ++ ++#define MSG(args) do{ /* args should be in brackets */ \ ++ _mali_osk_dbgmsg("UMP: "); \ ++ _mali_osk_dbgmsg args; \ ++ } while (0) ++ ++ ++ ++/* ++ * This struct is used to store per session data. ++ * A session is created when someone open() the device, and ++ * closed when someone close() it or the user space application terminates. ++ */ ++typedef struct ump_session_data { ++ _mali_osk_list_t list_head_session_memory_list; /**< List of ump allocations made by the process (elements are ump_session_memory_list_element) */ ++ _mali_osk_list_t list_head_session_memory_mappings_list; /**< List of ump_memory_allocations mapped in */ ++ int api_version; ++ _mali_osk_mutex_t *lock; ++ ump_descriptor_mapping * cookies_map; /**< Secure mapping of cookies from _ump_ukk_map_mem() */ ++ int cache_operations_ongoing; ++ int has_pending_level1_cache_flush; ++} ump_session_data; ++ ++ ++ ++/* ++ * This struct is used to track the UMP memory references a session has. ++ * We need to track this in order to be able to clean up after user space processes ++ * which don't do it themself (e.g. due to a crash or premature termination). ++ */ ++typedef struct ump_session_memory_list_element { ++ struct ump_dd_mem * mem; ++ _mali_osk_list_t list; ++} ump_session_memory_list_element; ++ ++ ++ ++/* ++ * Device specific data, created when device driver is loaded, and then kept as the global variable device. ++ */ ++typedef struct ump_dev { ++ _mali_osk_mutex_t *secure_id_map_lock; ++ ump_descriptor_mapping * secure_id_map; ++ ump_memory_backend * backend; ++} ump_dev; ++ ++ ++ ++extern int ump_debug_level; ++extern struct ump_dev device; ++ ++_mali_osk_errcode_t ump_kernel_constructor(void); ++void ump_kernel_destructor(void); ++int map_errcode( _mali_osk_errcode_t err ); ++ ++/** ++ * variables from user space cannot be dereferenced from kernel space; tagging them ++ * with __user allows the GCC compiler to generate a warning. Other compilers may ++ * not support this so we define it here as an empty macro if the compiler doesn't ++ * define it. ++ */ ++#ifndef __user ++#define __user ++#endif ++ ++#endif /* __UMP_KERNEL_COMMON_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.c +new file mode 100644 +index 0000000..ab4e01e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.c +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_kernel_common.h" ++#include "mali_osk.h" ++#include "mali_osk_bitops.h" ++#include "ump_kernel_common.h" ++#include "ump_kernel_descriptor_mapping.h" ++ ++#define MALI_PAD_INT(x) (((x) + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1)) ++ ++/** ++ * Allocate a descriptor table capable of holding 'count' mappings ++ * @param count Number of mappings in the table ++ * @return Pointer to a new table, NULL on error ++ */ ++static ump_descriptor_table * descriptor_table_alloc(int count); ++ ++/** ++ * Free a descriptor table ++ * @param table The table to free ++ */ ++static void descriptor_table_free(ump_descriptor_table * table); ++ ++ump_descriptor_mapping * ump_descriptor_mapping_create(int init_entries, int max_entries) ++{ ++ ump_descriptor_mapping * map = _mali_osk_calloc(1, sizeof(ump_descriptor_mapping) ); ++ ++ init_entries = MALI_PAD_INT(init_entries); ++ max_entries = MALI_PAD_INT(max_entries); ++ ++ if (NULL != map) { ++ map->table = descriptor_table_alloc(init_entries); ++ if (NULL != map->table) { ++ map->lock = _mali_osk_mutex_rw_init(_MALI_OSK_LOCKFLAG_UNORDERED, 0); ++ if ( NULL != map->lock ) { ++ _mali_osk_set_nonatomic_bit(0, map->table->usage); /* reserve bit 0 to prevent NULL/zero logic to kick in */ ++ map->max_nr_mappings_allowed = max_entries; ++ map->current_nr_mappings = init_entries; ++ return map; ++ } ++ descriptor_table_free(map->table); ++ } ++ _mali_osk_free(map); ++ } ++ return NULL; ++} ++ ++void ump_descriptor_mapping_destroy(ump_descriptor_mapping * map) ++{ ++ descriptor_table_free(map->table); ++ _mali_osk_mutex_rw_term(map->lock); ++ _mali_osk_free(map); ++} ++ ++int ump_descriptor_mapping_allocate_mapping(ump_descriptor_mapping * map, void * target) ++{ ++ int descriptor = -1;/*-EFAULT;*/ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW); ++ descriptor = _mali_osk_find_first_zero_bit(map->table->usage, map->current_nr_mappings); ++ if (descriptor == map->current_nr_mappings) { ++ int nr_mappings_new; ++ /* no free descriptor, try to expand the table */ ++ ump_descriptor_table * new_table; ++ ump_descriptor_table * old_table = map->table; ++ nr_mappings_new= map->current_nr_mappings *2; ++ ++ if (map->current_nr_mappings >= map->max_nr_mappings_allowed) { ++ descriptor = -1; ++ goto unlock_and_exit; ++ } ++ ++ new_table = descriptor_table_alloc(nr_mappings_new); ++ if (NULL == new_table) { ++ descriptor = -1; ++ goto unlock_and_exit; ++ } ++ ++ _mali_osk_memcpy(new_table->usage, old_table->usage, (sizeof(unsigned long)*map->current_nr_mappings) / BITS_PER_LONG); ++ _mali_osk_memcpy(new_table->mappings, old_table->mappings, map->current_nr_mappings * sizeof(void*)); ++ map->table = new_table; ++ map->current_nr_mappings = nr_mappings_new; ++ descriptor_table_free(old_table); ++ } ++ ++ /* we have found a valid descriptor, set the value and usage bit */ ++ _mali_osk_set_nonatomic_bit(descriptor, map->table->usage); ++ map->table->mappings[descriptor] = target; ++ ++unlock_and_exit: ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW); ++ return descriptor; ++} ++ ++int ump_descriptor_mapping_get(ump_descriptor_mapping * map, int descriptor, void** target) ++{ ++ int result = -1;/*-EFAULT;*/ ++ DEBUG_ASSERT(map); ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO); ++ if ((descriptor > 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage)) { ++ *target = map->table->mappings[descriptor]; ++ result = 0; ++ } else *target = NULL; ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO); ++ return result; ++} ++ ++int ump_descriptor_mapping_set(ump_descriptor_mapping * map, int descriptor, void * target) ++{ ++ int result = -1;/*-EFAULT;*/ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RO); ++ if ((descriptor > 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage)) { ++ map->table->mappings[descriptor] = target; ++ result = 0; ++ } ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RO); ++ return result; ++} ++ ++void ump_descriptor_mapping_free(ump_descriptor_mapping * map, int descriptor) ++{ ++ _mali_osk_mutex_rw_wait(map->lock, _MALI_OSK_LOCKMODE_RW); ++ if ((descriptor > 0) && (descriptor < map->current_nr_mappings) && _mali_osk_test_bit(descriptor, map->table->usage)) { ++ map->table->mappings[descriptor] = NULL; ++ _mali_osk_clear_nonatomic_bit(descriptor, map->table->usage); ++ } ++ _mali_osk_mutex_rw_signal(map->lock, _MALI_OSK_LOCKMODE_RW); ++} ++ ++static ump_descriptor_table * descriptor_table_alloc(int count) ++{ ++ ump_descriptor_table * table; ++ ++ table = _mali_osk_calloc(1, sizeof(ump_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG) + (sizeof(void*) * count) ); ++ ++ if (NULL != table) { ++ table->usage = (u32*)((u8*)table + sizeof(ump_descriptor_table)); ++ table->mappings = (void**)((u8*)table + sizeof(ump_descriptor_table) + ((sizeof(unsigned long) * count)/BITS_PER_LONG)); ++ } ++ ++ return table; ++} ++ ++static void descriptor_table_free(ump_descriptor_table * table) ++{ ++ _mali_osk_free(table); ++} ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.h +new file mode 100644 +index 0000000..a351d3a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_descriptor_mapping.h +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_descriptor_mapping.h ++ */ ++ ++#ifndef __UMP_KERNEL_DESCRIPTOR_MAPPING_H__ ++#define __UMP_KERNEL_DESCRIPTOR_MAPPING_H__ ++ ++#include "mali_osk.h" ++ ++/** ++ * The actual descriptor mapping table, never directly accessed by clients ++ */ ++typedef struct ump_descriptor_table { ++ u32 * usage; /**< Pointer to bitpattern indicating if a descriptor is valid/used or not */ ++ void** mappings; /**< Array of the pointers the descriptors map to */ ++} ump_descriptor_table; ++ ++/** ++ * The descriptor mapping object ++ * Provides a separate namespace where we can map an integer to a pointer ++ */ ++typedef struct ump_descriptor_mapping { ++ _mali_osk_mutex_rw_t *lock; /**< Lock protecting access to the mapping object */ ++ int max_nr_mappings_allowed; /**< Max number of mappings to support in this namespace */ ++ int current_nr_mappings; /**< Current number of possible mappings */ ++ ump_descriptor_table * table; /**< Pointer to the current mapping table */ ++} ump_descriptor_mapping; ++ ++/** ++ * Create a descriptor mapping object ++ * Create a descriptor mapping capable of holding init_entries growable to max_entries ++ * @param init_entries Number of entries to preallocate memory for ++ * @param max_entries Number of entries to max support ++ * @return Pointer to a descriptor mapping object, NULL on failure ++ */ ++ump_descriptor_mapping * ump_descriptor_mapping_create(int init_entries, int max_entries); ++ ++/** ++ * Destroy a descriptor mapping object ++ * @param map The map to free ++ */ ++void ump_descriptor_mapping_destroy(ump_descriptor_mapping * map); ++ ++/** ++ * Allocate a new mapping entry (descriptor ID) ++ * Allocates a new entry in the map. ++ * @param map The map to allocate a new entry in ++ * @param target The value to map to ++ * @return The descriptor allocated, a negative value on error ++ */ ++int ump_descriptor_mapping_allocate_mapping(ump_descriptor_mapping * map, void * target); ++ ++/** ++ * Get the value mapped to by a descriptor ID ++ * @param map The map to lookup the descriptor id in ++ * @param descriptor The descriptor ID to lookup ++ * @param target Pointer to a pointer which will receive the stored value ++ * @return 0 on successful lookup, negative on error ++ */ ++int ump_descriptor_mapping_get(ump_descriptor_mapping * map, int descriptor, void** target); ++ ++/** ++ * Set the value mapped to by a descriptor ID ++ * @param map The map to lookup the descriptor id in ++ * @param descriptor The descriptor ID to lookup ++ * @param target Pointer to replace the current value with ++ * @return 0 on successful lookup, negative on error ++ */ ++int ump_descriptor_mapping_set(ump_descriptor_mapping * map, int descriptor, void * target); ++ ++/** ++ * Free the descriptor ID ++ * For the descriptor to be reused it has to be freed ++ * @param map The map to free the descriptor from ++ * @param descriptor The descriptor ID to free ++ */ ++void ump_descriptor_mapping_free(ump_descriptor_mapping * map, int descriptor); ++ ++#endif /* __UMP_KERNEL_DESCRIPTOR_MAPPING_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_memory_backend.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_memory_backend.h +new file mode 100644 +index 0000000..705c705 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_memory_backend.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_memory_mapping.h ++ */ ++ ++#ifndef __UMP_KERNEL_MEMORY_BACKEND_H__ ++#define __UMP_KERNEL_MEMORY_BACKEND_H__ ++ ++#include "ump_kernel_interface.h" ++#include "ump_kernel_types.h" ++ ++ ++typedef struct ump_memory_allocation { ++ void * phys_addr; ++ void * mapping; ++ unsigned long size; ++ ump_dd_handle handle; ++ void * process_mapping_info; ++ u32 cookie; /**< necessary on some U/K interface implementations */ ++ struct ump_session_data * ump_session; /**< Session that this allocation belongs to */ ++ _mali_osk_list_t list; /**< List for linking together memory allocations into the session's memory head */ ++ u32 is_cached; ++} ump_memory_allocation; ++ ++typedef struct ump_memory_backend { ++ int (*allocate)(void* ctx, ump_dd_mem * descriptor); ++ void (*release)(void* ctx, ump_dd_mem * descriptor); ++ void (*shutdown)(struct ump_memory_backend * backend); ++ u32 (*stat)(struct ump_memory_backend *backend); ++ int (*pre_allocate_physical_check)(void *ctx, u32 size); ++ u32 (*adjust_to_mali_phys)(void *ctx, u32 cpu_phys); ++ void * ctx; ++} ump_memory_backend; ++ ++ump_memory_backend * ump_memory_backend_create ( void ); ++void ump_memory_backend_destroy( void ); ++ ++#endif /*__UMP_KERNEL_MEMORY_BACKEND_H__ */ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_ref_drv.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_ref_drv.c +new file mode 100644 +index 0000000..99eb172 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_ref_drv.c +@@ -0,0 +1,186 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "mali_osk.h" ++#include "mali_osk_list.h" ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++ ++#include "ump_kernel_interface_ref_drv.h" ++#include "ump_kernel_common.h" ++#include "ump_kernel_descriptor_mapping.h" ++ ++#define UMP_MINIMUM_SIZE 4096 ++#define UMP_MINIMUM_SIZE_MASK (~(UMP_MINIMUM_SIZE-1)) ++#define UMP_SIZE_ALIGN(x) (((x)+UMP_MINIMUM_SIZE-1)&UMP_MINIMUM_SIZE_MASK) ++#define UMP_ADDR_ALIGN_OFFSET(x) ((x)&(UMP_MINIMUM_SIZE-1)) ++static void phys_blocks_release(void * ctx, struct ump_dd_mem * descriptor); ++ ++UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block * blocks, unsigned long num_blocks) ++{ ++ ump_dd_mem * mem; ++ unsigned long size_total = 0; ++ int map_id; ++ u32 i; ++ ++ /* Go through the input blocks and verify that they are sane */ ++ for (i=0; i < num_blocks; i++) { ++ unsigned long addr = blocks[i].addr; ++ unsigned long size = blocks[i].size; ++ ++ DBG_MSG(5, ("Adding physical memory to new handle. Address: 0x%08lx, size: %lu\n", addr, size)); ++ size_total += blocks[i].size; ++ ++ if (0 != UMP_ADDR_ALIGN_OFFSET(addr)) { ++ MSG_ERR(("Trying to create UMP memory from unaligned physical address. Address: 0x%08lx\n", addr)); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ ++ if (0 != UMP_ADDR_ALIGN_OFFSET(size)) { ++ MSG_ERR(("Trying to create UMP memory with unaligned size. Size: %lu\n", size)); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ } ++ ++ /* Allocate the ump_dd_mem struct for this allocation */ ++ mem = _mali_osk_malloc(sizeof(*mem)); ++ if (NULL == mem) { ++ DBG_MSG(1, ("Could not allocate ump_dd_mem in ump_dd_handle_create_from_phys_blocks()\n")); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ ++ /* Find a secure ID for this allocation */ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ map_id = ump_descriptor_mapping_allocate_mapping(device.secure_id_map, (void*) mem); ++ ++ if (map_id < 0) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ _mali_osk_free(mem); ++ DBG_MSG(1, ("Failed to allocate secure ID in ump_dd_handle_create_from_phys_blocks()\n")); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ ++ /* Now, make a copy of the block information supplied by the user */ ++ mem->block_array = _mali_osk_malloc(sizeof(ump_dd_physical_block)* num_blocks); ++ if (NULL == mem->block_array) { ++ ump_descriptor_mapping_free(device.secure_id_map, map_id); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ _mali_osk_free(mem); ++ DBG_MSG(1, ("Could not allocate a mem handle for function ump_dd_handle_create_from_phys_blocks().\n")); ++ return UMP_DD_HANDLE_INVALID; ++ } ++ ++ _mali_osk_memcpy(mem->block_array, blocks, sizeof(ump_dd_physical_block) * num_blocks); ++ ++ /* And setup the rest of the ump_dd_mem struct */ ++ _mali_osk_atomic_init(&mem->ref_count, 1); ++ mem->secure_id = (ump_secure_id)map_id; ++ mem->size_bytes = size_total; ++ mem->nr_blocks = num_blocks; ++ mem->backend_info = NULL; ++ mem->ctx = NULL; ++ mem->release_func = phys_blocks_release; ++ /* For now UMP handles created by ump_dd_handle_create_from_phys_blocks() is forced to be Uncached */ ++ mem->is_cached = 0; ++ mem->hw_device = _UMP_UK_USED_BY_CPU; ++ mem->lock_usage = UMP_NOT_LOCKED; ++ ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ DBG_MSG(3, ("UMP memory created. ID: %u, size: %lu\n", mem->secure_id, mem->size_bytes)); ++ ++ return (ump_dd_handle)mem; ++} ++ ++static void phys_blocks_release(void * ctx, struct ump_dd_mem * descriptor) ++{ ++ _mali_osk_free(descriptor->block_array); ++ descriptor->block_array = NULL; ++} ++ ++_mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction ) ++{ ++ ump_session_data * session_data = NULL; ++ ump_dd_mem *new_allocation = NULL; ++ ump_session_memory_list_element * session_memory_element = NULL; ++ int map_id; ++ ++ DEBUG_ASSERT_POINTER( user_interaction ); ++ DEBUG_ASSERT_POINTER( user_interaction->ctx ); ++ ++ session_data = (ump_session_data *) user_interaction->ctx; ++ ++ session_memory_element = _mali_osk_calloc( 1, sizeof(ump_session_memory_list_element)); ++ if (NULL == session_memory_element) { ++ DBG_MSG(1, ("Failed to allocate ump_session_memory_list_element in ump_ioctl_allocate()\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ ++ new_allocation = _mali_osk_calloc( 1, sizeof(ump_dd_mem)); ++ if (NULL==new_allocation) { ++ _mali_osk_free(session_memory_element); ++ DBG_MSG(1, ("Failed to allocate ump_dd_mem in _ump_ukk_allocate()\n")); ++ return _MALI_OSK_ERR_NOMEM; ++ } ++ ++ /* Create a secure ID for this allocation */ ++ _mali_osk_mutex_wait(device.secure_id_map_lock); ++ map_id = ump_descriptor_mapping_allocate_mapping(device.secure_id_map, (void*)new_allocation); ++ ++ if (map_id < 0) { ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ _mali_osk_free(session_memory_element); ++ _mali_osk_free(new_allocation); ++ DBG_MSG(1, ("Failed to allocate secure ID in ump_ioctl_allocate()\n")); ++ return - _MALI_OSK_ERR_INVALID_FUNC; ++ } ++ ++ /* Initialize the part of the new_allocation that we know so for */ ++ new_allocation->secure_id = (ump_secure_id)map_id; ++ _mali_osk_atomic_init(&new_allocation->ref_count,1); ++ if ( 0==(UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE & user_interaction->constraints) ) ++ new_allocation->is_cached = 0; ++ else new_allocation->is_cached = 1; ++ ++ /* special case a size of 0, we should try to emulate what malloc does in this case, which is to return a valid pointer that must be freed, but can't be dereferences */ ++ if (0 == user_interaction->size) { ++ user_interaction->size = 1; /* emulate by actually allocating the minimum block size */ ++ } ++ ++ new_allocation->size_bytes = UMP_SIZE_ALIGN(user_interaction->size); /* Page align the size */ ++ new_allocation->lock_usage = UMP_NOT_LOCKED; ++ ++ /* Now, ask the active memory backend to do the actual memory allocation */ ++ if (!device.backend->allocate( device.backend->ctx, new_allocation ) ) { ++ DBG_MSG(3, ("OOM: No more UMP memory left. Failed to allocate memory in ump_ioctl_allocate(). Size: %lu, requested size: %lu\n", new_allocation->size_bytes, (unsigned long)user_interaction->size)); ++ ump_descriptor_mapping_free(device.secure_id_map, map_id); ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ _mali_osk_free(new_allocation); ++ _mali_osk_free(session_memory_element); ++ return _MALI_OSK_ERR_INVALID_FUNC; ++ } ++ new_allocation->hw_device = _UMP_UK_USED_BY_CPU; ++ new_allocation->ctx = device.backend->ctx; ++ new_allocation->release_func = device.backend->release; ++ ++ _mali_osk_mutex_signal(device.secure_id_map_lock); ++ ++ /* Initialize the session_memory_element, and add it to the session object */ ++ session_memory_element->mem = new_allocation; ++ _mali_osk_mutex_wait(session_data->lock); ++ _mali_osk_list_add(&(session_memory_element->list), &(session_data->list_head_session_memory_list)); ++ _mali_osk_mutex_signal(session_data->lock); ++ ++ user_interaction->secure_id = new_allocation->secure_id; ++ user_interaction->size = new_allocation->size_bytes; ++ DBG_MSG(3, ("UMP memory allocated. ID: %u, size: %lu\n", new_allocation->secure_id, new_allocation->size_bytes)); ++ ++ return _MALI_OSK_ERR_OK; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_types.h +new file mode 100644 +index 0000000..08704ab +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_kernel_types.h +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __UMP_KERNEL_TYPES_H__ ++#define __UMP_KERNEL_TYPES_H__ ++ ++#include "ump_kernel_interface.h" ++#include "mali_osk.h" ++ ++ ++typedef enum { ++ UMP_USED_BY_CPU = 0, ++ UMP_USED_BY_MALI = 1, ++ UMP_USED_BY_UNKNOWN_DEVICE= 100, ++} ump_hw_usage; ++ ++typedef enum { ++ UMP_NOT_LOCKED = 0, ++ UMP_READ = 1, ++ UMP_READ_WRITE = 3, ++} ump_lock_usage; ++ ++ ++/* ++ * This struct is what is "behind" a ump_dd_handle ++ */ ++typedef struct ump_dd_mem { ++ ump_secure_id secure_id; ++ _mali_osk_atomic_t ref_count; ++ unsigned long size_bytes; ++ unsigned long nr_blocks; ++ ump_dd_physical_block * block_array; ++ void (*release_func)(void * ctx, struct ump_dd_mem * descriptor); ++ void * ctx; ++ void * backend_info; ++ int is_cached; ++ ump_hw_usage hw_device; ++ ump_lock_usage lock_usage; ++} ump_dd_mem; ++ ++ ++ ++#endif /* __UMP_KERNEL_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_osk.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_osk.h +new file mode 100644 +index 0000000..9b048aa +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_osk.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_osk.h ++ * Defines the OS abstraction layer for the UMP kernel device driver (OSK) ++ */ ++ ++#ifndef __UMP_OSK_H__ ++#define __UMP_OSK_H__ ++ ++#include ++#include ++#include "ump_uk_types.h" ++#include "ump_kernel_common.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++_mali_osk_errcode_t _ump_osk_init( void ); ++ ++_mali_osk_errcode_t _ump_osk_term( void ); ++ ++int _ump_osk_atomic_inc_and_read( _mali_osk_atomic_t *atom ); ++ ++int _ump_osk_atomic_dec_and_read( _mali_osk_atomic_t *atom ); ++ ++_mali_osk_errcode_t _ump_osk_mem_mapregion_init( ump_memory_allocation *descriptor ); ++ ++_mali_osk_errcode_t _ump_osk_mem_mapregion_map( ump_memory_allocation * descriptor, u32 offset, u32 * phys_addr, unsigned long size ); ++ ++void _ump_osk_mem_mapregion_term( ump_memory_allocation * descriptor ); ++ ++void _ump_osk_msync( ump_dd_mem * mem, void * virt, u32 offset, u32 size, ump_uk_msync_op op, ump_session_data * session_data ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_uk_types.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_uk_types.h +new file mode 100644 +index 0000000..ead1258 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_uk_types.h +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_uk_types.h ++ * Defines the types and constants used in the user-kernel interface ++ */ ++ ++#ifndef __UMP_UK_TYPES_H__ ++#define __UMP_UK_TYPES_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Helpers for API version handling */ ++#define MAKE_VERSION_ID(x) (((x) << 16UL) | (x)) ++#define IS_VERSION_ID(x) (((x) & 0xFFFF) == (((x) >> 16UL) & 0xFFFF)) ++#define GET_VERSION(x) (((x) >> 16UL) & 0xFFFF) ++#define IS_API_MATCH(x, y) (IS_VERSION_ID((x)) && IS_VERSION_ID((y)) && (GET_VERSION((x)) == GET_VERSION((y)))) ++ ++/** ++ * API version define. ++ * Indicates the version of the kernel API ++ * The version is a 16bit integer incremented on each API change. ++ * The 16bit integer is stored twice in a 32bit integer ++ * So for version 1 the value would be 0x00010001 ++ */ ++#define UMP_IOCTL_API_VERSION MAKE_VERSION_ID(2) ++ ++typedef enum ++{ ++ _UMP_IOC_QUERY_API_VERSION = 1, ++ _UMP_IOC_ALLOCATE, ++ _UMP_IOC_RELEASE, ++ _UMP_IOC_SIZE_GET, ++ _UMP_IOC_MAP_MEM, /* not used in Linux */ ++ _UMP_IOC_UNMAP_MEM, /* not used in Linux */ ++ _UMP_IOC_MSYNC, ++ _UMP_IOC_CACHE_OPERATIONS_CONTROL, ++ _UMP_IOC_SWITCH_HW_USAGE, ++ _UMP_IOC_LOCK, ++ _UMP_IOC_UNLOCK, ++} _ump_uk_functions; ++ ++typedef enum ++{ ++ UMP_REF_DRV_UK_CONSTRAINT_NONE = 0, ++ UMP_REF_DRV_UK_CONSTRAINT_PHYSICALLY_LINEAR = 1, ++ UMP_REF_DRV_UK_CONSTRAINT_USE_CACHE = 4, ++} ump_uk_alloc_constraints; ++ ++typedef enum ++{ ++ _UMP_UK_MSYNC_CLEAN = 0, ++ _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE = 1, ++ _UMP_UK_MSYNC_INVALIDATE = 2, ++ _UMP_UK_MSYNC_FLUSH_L1 = 3, ++ _UMP_UK_MSYNC_READOUT_CACHE_ENABLED = 128, ++} ump_uk_msync_op; ++ ++typedef enum ++{ ++ _UMP_UK_CACHE_OP_START = 0, ++ _UMP_UK_CACHE_OP_FINISH = 1, ++} ump_uk_cache_op_control; ++ ++typedef enum ++{ ++ _UMP_UK_READ = 1, ++ _UMP_UK_READ_WRITE = 3, ++} ump_uk_lock_usage; ++ ++typedef enum ++{ ++ _UMP_UK_USED_BY_CPU = 0, ++ _UMP_UK_USED_BY_MALI = 1, ++ _UMP_UK_USED_BY_UNKNOWN_DEVICE = 100, ++} ump_uk_user; ++ ++/** ++ * Get API version ([in,out] u32 api_version, [out] u32 compatible) ++ */ ++typedef struct _ump_uk_api_version_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 version; /**< Set to the user space version on entry, stores the device driver version on exit */ ++ u32 compatible; /**< Non-null if the device is compatible with the client */ ++} _ump_uk_api_version_s; ++ ++/** ++ * ALLOCATE ([out] u32 secure_id, [in,out] u32 size, [in] contraints) ++ */ ++typedef struct _ump_uk_allocate_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< Return value from DD to Userdriver */ ++ u32 size; /**< Input and output. Requested size; input. Returned size; output */ ++ ump_uk_alloc_constraints constraints; /**< Only input to Devicedriver */ ++} _ump_uk_allocate_s; ++ ++/** ++ * SIZE_GET ([in] u32 secure_id, [out]size ) ++ */ ++typedef struct _ump_uk_size_get_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< Input to DD */ ++ u32 size; /**< Returned size; output */ ++} _ump_uk_size_get_s; ++ ++/** ++ * Release ([in] u32 secure_id) ++ */ ++typedef struct _ump_uk_release_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< Input to DD */ ++} _ump_uk_release_s; ++ ++typedef struct _ump_uk_map_mem_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *mapping; /**< [out] Returns user-space virtual address for the mapping */ ++ void *phys_addr; /**< [in] physical address */ ++ unsigned long size; /**< [in] size */ ++ u32 secure_id; /**< [in] secure_id to assign to mapping */ ++ void *_ukk_private; /**< Only used inside linux port between kernel frontend and common part to store vma */ ++ u32 cookie; ++ u32 is_cached; /**< [in,out] caching of CPU mappings */ ++} _ump_uk_map_mem_s; ++ ++typedef struct _ump_uk_unmap_mem_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *mapping; ++ u32 size; ++ void *_ukk_private; ++ u32 cookie; ++} _ump_uk_unmap_mem_s; ++ ++typedef struct _ump_uk_msync_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ void *mapping; /**< [in] mapping addr */ ++ void *address; /**< [in] flush start addr */ ++ u32 size; /**< [in] size to flush */ ++ ump_uk_msync_op op; /**< [in] flush operation */ ++ u32 cookie; /**< [in] cookie stored with reference to the kernel mapping internals */ ++ u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ ++ u32 is_cached; /**< [out] caching of CPU mappings */ ++} _ump_uk_msync_s; ++ ++typedef struct _ump_uk_cache_operations_control_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ ump_uk_cache_op_control op; /**< [in] cache operations start/stop */ ++} _ump_uk_cache_operations_control_s; ++ ++ ++typedef struct _ump_uk_switch_hw_usage_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ ++ ump_uk_user new_user; /**< [in] cookie stored with reference to the kernel mapping internals */ ++ ++} _ump_uk_switch_hw_usage_s; ++ ++typedef struct _ump_uk_lock_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ ++ ump_uk_lock_usage lock_usage; ++} _ump_uk_lock_s; ++ ++typedef struct _ump_uk_unlock_s ++{ ++ void *ctx; /**< [in,out] user-kernel context (trashed on output) */ ++ u32 secure_id; /**< [in] secure_id that identifies the ump buffer */ ++} _ump_uk_unlock_s; ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_UK_TYPES_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_ukk.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_ukk.h +new file mode 100644 +index 0000000..568a428 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/common/ump_ukk.h +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_ukk.h ++ * Defines the kernel-side interface of the user-kernel interface ++ */ ++ ++#ifndef __UMP_UKK_H__ ++#define __UMP_UKK_H__ ++ ++#include "mali_osk.h" ++#include "ump_uk_types.h" ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++_mali_osk_errcode_t _ump_ukk_open( void** context ); ++ ++_mali_osk_errcode_t _ump_ukk_close( void** context ); ++ ++_mali_osk_errcode_t _ump_ukk_allocate( _ump_uk_allocate_s *user_interaction ); ++ ++_mali_osk_errcode_t _ump_ukk_release( _ump_uk_release_s *release_info ); ++ ++_mali_osk_errcode_t _ump_ukk_size_get( _ump_uk_size_get_s *user_interaction ); ++ ++_mali_osk_errcode_t _ump_ukk_map_mem( _ump_uk_map_mem_s *args ); ++ ++_mali_osk_errcode_t _ump_uku_get_api_version( _ump_uk_api_version_s *args ); ++ ++void _ump_ukk_unmap_mem( _ump_uk_unmap_mem_s *args ); ++ ++void _ump_ukk_msync( _ump_uk_msync_s *args ); ++ ++void _ump_ukk_cache_operations_control(_ump_uk_cache_operations_control_s* args); ++ ++void _ump_ukk_switch_hw_usage(_ump_uk_switch_hw_usage_s *args ); ++ ++void _ump_ukk_lock(_ump_uk_lock_s *args ); ++ ++void _ump_ukk_unlock(_ump_uk_unlock_s *args ); ++ ++u32 _ump_ukk_report_memory_usage( void ); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_UKK_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/license/gpl/ump_kernel_license.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/license/gpl/ump_kernel_license.h +new file mode 100644 +index 0000000..4db4538 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/license/gpl/ump_kernel_license.h +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_license.h ++ * Defines for the macro MODULE_LICENSE. ++ */ ++ ++#ifndef __UMP_KERNEL_LICENSE_H__ ++#define __UMP_KERNEL_LICENSE_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#define UMP_KERNEL_LINUX_LICENSE "GPL" ++#define UMP_LICENSE_IS_GPL 1 ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_KERNEL_LICENSE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ioctl.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ioctl.h +new file mode 100644 +index 0000000..51787f6 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ioctl.h +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __UMP_IOCTL_H__ ++#define __UMP_IOCTL_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++#include ++ ++#include ++ ++#ifndef __user ++#define __user ++#endif ++ ++ ++/** ++ * @file UMP_ioctl.h ++ * This file describes the interface needed to use the Linux device driver. ++ * The interface is used by the userpace UMP driver. ++ */ ++ ++#define UMP_IOCTL_NR 0x90 ++ ++ ++#define UMP_IOC_QUERY_API_VERSION _IOR(UMP_IOCTL_NR, _UMP_IOC_QUERY_API_VERSION, _ump_uk_api_version_s) ++#define UMP_IOC_ALLOCATE _IOWR(UMP_IOCTL_NR, _UMP_IOC_ALLOCATE, _ump_uk_allocate_s) ++#define UMP_IOC_RELEASE _IOR(UMP_IOCTL_NR, _UMP_IOC_RELEASE, _ump_uk_release_s) ++#define UMP_IOC_SIZE_GET _IOWR(UMP_IOCTL_NR, _UMP_IOC_SIZE_GET, _ump_uk_size_get_s) ++#define UMP_IOC_MSYNC _IOW(UMP_IOCTL_NR, _UMP_IOC_MSYNC, _ump_uk_msync_s) ++ ++#define UMP_IOC_CACHE_OPERATIONS_CONTROL _IOW(UMP_IOCTL_NR, _UMP_IOC_CACHE_OPERATIONS_CONTROL, _ump_uk_cache_operations_control_s) ++#define UMP_IOC_SWITCH_HW_USAGE _IOW(UMP_IOCTL_NR, _UMP_IOC_SWITCH_HW_USAGE, _ump_uk_switch_hw_usage_s) ++#define UMP_IOC_LOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_LOCK, _ump_uk_lock_s) ++#define UMP_IOC_UNLOCK _IOW(UMP_IOCTL_NR, _UMP_IOC_UNLOCK, _ump_uk_unlock_s) ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_IOCTL_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.c +new file mode 100644 +index 0000000..b22585d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.c +@@ -0,0 +1,447 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include /* kernel module definitions */ ++#include /* file system operations */ ++#include /* character device definitions */ ++#include /* request_mem_region */ ++#include /* memory management functions and types */ ++#include /* user space access */ ++#include ++#include ++#include ++ ++#include "arch/config.h" /* Configuration for current platform. The symlinc for arch is set by Makefile */ ++#include "ump_ioctl.h" ++#include "ump_kernel_common.h" ++#include "ump_kernel_interface.h" ++#include "ump_kernel_interface_ref_drv.h" ++#include "ump_kernel_descriptor_mapping.h" ++#include "ump_kernel_memory_backend.h" ++#include "ump_kernel_memory_backend_os.h" ++#include "ump_kernel_memory_backend_dedicated.h" ++#include "ump_kernel_license.h" ++ ++#include "ump_osk.h" ++#include "ump_ukk.h" ++#include "ump_uk_types.h" ++#include "ump_ukk_wrappers.h" ++#include "ump_ukk_ref_wrappers.h" ++ ++ ++/* Module parameter to control log level */ ++int ump_debug_level = 2; ++module_param(ump_debug_level, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); /* rw-rw-r-- */ ++MODULE_PARM_DESC(ump_debug_level, "Higher number, more dmesg output"); ++ ++/* By default the module uses any available major, but it's possible to set it at load time to a specific number */ ++int ump_major = 0; ++module_param(ump_major, int, S_IRUGO); /* r--r--r-- */ ++MODULE_PARM_DESC(ump_major, "Device major number"); ++ ++/* Name of the UMP device driver */ ++static char ump_dev_name[] = "ump"; /* should be const, but the functions we call requires non-cost */ ++ ++ ++#if UMP_LICENSE_IS_GPL ++static struct dentry *ump_debugfs_dir = NULL; ++#endif ++ ++/* ++ * The data which we attached to each virtual memory mapping request we get. ++ * Each memory mapping has a reference to the UMP memory it maps. ++ * We release this reference when the last memory mapping is unmapped. ++ */ ++typedef struct ump_vma_usage_tracker { ++ int references; ++ ump_dd_handle handle; ++} ump_vma_usage_tracker; ++ ++struct ump_device { ++ struct cdev cdev; ++#if UMP_LICENSE_IS_GPL ++ struct class * ump_class; ++#endif ++}; ++ ++/* The global variable containing the global device data */ ++static struct ump_device ump_device; ++ ++ ++/* Forward declare static functions */ ++static int ump_file_open(struct inode *inode, struct file *filp); ++static int ump_file_release(struct inode *inode, struct file *filp); ++#ifdef HAVE_UNLOCKED_IOCTL ++static long ump_file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); ++#else ++static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); ++#endif ++static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma); ++ ++ ++/* This variable defines the file operations this UMP device driver offer */ ++static struct file_operations ump_fops = { ++ .owner = THIS_MODULE, ++ .open = ump_file_open, ++ .release = ump_file_release, ++#ifdef HAVE_UNLOCKED_IOCTL ++ .unlocked_ioctl = ump_file_ioctl, ++#else ++ .ioctl = ump_file_ioctl, ++#endif ++ .mmap = ump_file_mmap ++}; ++ ++ ++/* This function is called by Linux to initialize this module. ++ * All we do is initialize the UMP device driver. ++ */ ++static int ump_initialize_module(void) ++{ ++ _mali_osk_errcode_t err; ++ ++ DBG_MSG(2, ("Inserting UMP device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__)); ++ ++ err = ump_kernel_constructor(); ++ if (_MALI_OSK_ERR_OK != err) { ++ MSG_ERR(("UMP device driver init failed\n")); ++ return map_errcode(err); ++ } ++ ++ MSG(("UMP device driver %s loaded\n", SVN_REV_STRING)); ++ return 0; ++} ++ ++ ++ ++/* ++ * This function is called by Linux to unload/terminate/exit/cleanup this module. ++ * All we do is terminate the UMP device driver. ++ */ ++static void ump_cleanup_module(void) ++{ ++ DBG_MSG(2, ("Unloading UMP device driver\n")); ++ ump_kernel_destructor(); ++ DBG_MSG(2, ("Module unloaded\n")); ++} ++ ++ ++ ++static ssize_t ump_memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) ++{ ++ char buf[64]; ++ size_t r; ++ u32 mem = _ump_ukk_report_memory_usage(); ++ ++ r = snprintf(buf, 64, "%u\n", mem); ++ return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); ++} ++ ++static const struct file_operations ump_memory_usage_fops = { ++ .owner = THIS_MODULE, ++ .read = ump_memory_used_read, ++}; ++ ++/* ++ * Initialize the UMP device driver. ++ */ ++int ump_kernel_device_initialize(void) ++{ ++ int err; ++ dev_t dev = 0; ++#if UMP_LICENSE_IS_GPL ++ ump_debugfs_dir = debugfs_create_dir(ump_dev_name, NULL); ++ if (ERR_PTR(-ENODEV) == ump_debugfs_dir) { ++ ump_debugfs_dir = NULL; ++ } else { ++ debugfs_create_file("memory_usage", 0400, ump_debugfs_dir, NULL, &ump_memory_usage_fops); ++ } ++#endif ++ ++ if (0 == ump_major) { ++ /* auto select a major */ ++ err = alloc_chrdev_region(&dev, 0, 1, ump_dev_name); ++ ump_major = MAJOR(dev); ++ } else { ++ /* use load time defined major number */ ++ dev = MKDEV(ump_major, 0); ++ err = register_chrdev_region(dev, 1, ump_dev_name); ++ } ++ ++ if (0 == err) { ++ memset(&ump_device, 0, sizeof(ump_device)); ++ ++ /* initialize our char dev data */ ++ cdev_init(&ump_device.cdev, &ump_fops); ++ ump_device.cdev.owner = THIS_MODULE; ++ ump_device.cdev.ops = &ump_fops; ++ ++ /* register char dev with the kernel */ ++ err = cdev_add(&ump_device.cdev, dev, 1/*count*/); ++ if (0 == err) { ++ ++#if UMP_LICENSE_IS_GPL ++ ump_device.ump_class = class_create(THIS_MODULE, ump_dev_name); ++ if (IS_ERR(ump_device.ump_class)) { ++ err = PTR_ERR(ump_device.ump_class); ++ } else { ++ struct device * mdev; ++ mdev = device_create(ump_device.ump_class, NULL, dev, NULL, ump_dev_name); ++ if (!IS_ERR(mdev)) { ++ return 0; ++ } ++ ++ err = PTR_ERR(mdev); ++ } ++ cdev_del(&ump_device.cdev); ++#else ++ return 0; ++#endif ++ } ++ ++ unregister_chrdev_region(dev, 1); ++ } ++ ++ return err; ++} ++ ++ ++ ++/* ++ * Terminate the UMP device driver ++ */ ++void ump_kernel_device_terminate(void) ++{ ++ dev_t dev = MKDEV(ump_major, 0); ++ ++#if UMP_LICENSE_IS_GPL ++ device_destroy(ump_device.ump_class, dev); ++ class_destroy(ump_device.ump_class); ++#endif ++ ++ /* unregister char device */ ++ cdev_del(&ump_device.cdev); ++ ++ /* free major */ ++ unregister_chrdev_region(dev, 1); ++ ++#if UMP_LICENSE_IS_GPL ++ if(ump_debugfs_dir) ++ debugfs_remove_recursive(ump_debugfs_dir); ++#endif ++} ++ ++/* ++ * Open a new session. User space has called open() on us. ++ */ ++static int ump_file_open(struct inode *inode, struct file *filp) ++{ ++ struct ump_session_data * session_data; ++ _mali_osk_errcode_t err; ++ ++ /* input validation */ ++ if (0 != MINOR(inode->i_rdev)) { ++ MSG_ERR(("Minor not zero in ump_file_open()\n")); ++ return -ENODEV; ++ } ++ ++ /* Call the OS-Independent UMP Open function */ ++ err = _ump_ukk_open((void**) &session_data ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ MSG_ERR(("Ump failed to open a new session\n")); ++ return map_errcode( err ); ++ } ++ ++ filp->private_data = (void*)session_data; ++ filp->f_pos = 0; ++ ++ return 0; /* success */ ++} ++ ++ ++ ++/* ++ * Close a session. User space has called close() or crashed/terminated. ++ */ ++static int ump_file_release(struct inode *inode, struct file *filp) ++{ ++ _mali_osk_errcode_t err; ++ ++ err = _ump_ukk_close((void**) &filp->private_data ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ return map_errcode( err ); ++ } ++ ++ return 0; /* success */ ++} ++ ++ ++ ++/* ++ * Handle IOCTL requests. ++ */ ++#ifdef HAVE_UNLOCKED_IOCTL ++static long ump_file_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ++#else ++static int ump_file_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) ++#endif ++{ ++ int err = -ENOTTY; ++ void __user * argument; ++ struct ump_session_data * session_data; ++ ++#ifndef HAVE_UNLOCKED_IOCTL ++ (void)inode; /* inode not used */ ++#endif ++ ++ session_data = (struct ump_session_data *)filp->private_data; ++ if (NULL == session_data) { ++ MSG_ERR(("No session data attached to file object\n")); ++ return -ENOTTY; ++ } ++ ++ /* interpret the argument as a user pointer to something */ ++ argument = (void __user *)arg; ++ ++ switch (cmd) { ++ case UMP_IOC_QUERY_API_VERSION: ++ err = ump_get_api_version_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_ALLOCATE : ++ err = ump_allocate_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_RELEASE: ++ err = ump_release_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_SIZE_GET: ++ err = ump_size_get_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_MSYNC: ++ err = ump_msync_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_CACHE_OPERATIONS_CONTROL: ++ err = ump_cache_operations_control_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_SWITCH_HW_USAGE: ++ err = ump_switch_hw_usage_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_LOCK: ++ err = ump_lock_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ case UMP_IOC_UNLOCK: ++ err = ump_unlock_wrapper((u32 __user *)argument, session_data); ++ break; ++ ++ default: ++ DBG_MSG(1, ("No handler for IOCTL. cmd: 0x%08x, arg: 0x%08lx\n", cmd, arg)); ++ err = -EFAULT; ++ break; ++ } ++ ++ return err; ++} ++ ++int map_errcode( _mali_osk_errcode_t err ) ++{ ++ switch(err) { ++ case _MALI_OSK_ERR_OK : ++ return 0; ++ case _MALI_OSK_ERR_FAULT: ++ return -EFAULT; ++ case _MALI_OSK_ERR_INVALID_FUNC: ++ return -ENOTTY; ++ case _MALI_OSK_ERR_INVALID_ARGS: ++ return -EINVAL; ++ case _MALI_OSK_ERR_NOMEM: ++ return -ENOMEM; ++ case _MALI_OSK_ERR_TIMEOUT: ++ return -ETIMEDOUT; ++ case _MALI_OSK_ERR_RESTARTSYSCALL: ++ return -ERESTARTSYS; ++ case _MALI_OSK_ERR_ITEM_NOT_FOUND: ++ return -ENOENT; ++ default: ++ return -EFAULT; ++ } ++} ++ ++/* ++ * Handle from OS to map specified virtual memory to specified UMP memory. ++ */ ++static int ump_file_mmap(struct file * filp, struct vm_area_struct * vma) ++{ ++ _ump_uk_map_mem_s args; ++ _mali_osk_errcode_t err; ++ struct ump_session_data * session_data; ++ ++ /* Validate the session data */ ++ session_data = (struct ump_session_data *)filp->private_data; ++ if (NULL == session_data) { ++ MSG_ERR(("mmap() called without any session data available\n")); ++ return -EFAULT; ++ } ++ ++ /* Re-pack the arguments that mmap() packed for us */ ++ args.ctx = session_data; ++ args.phys_addr = 0; ++ args.size = vma->vm_end - vma->vm_start; ++ args._ukk_private = vma; ++ args.secure_id = vma->vm_pgoff; ++ args.is_cached = 0; ++ ++ if (!(vma->vm_flags & VM_SHARED)) { ++ args.is_cached = 1; ++ vma->vm_flags = vma->vm_flags | VM_SHARED | VM_MAYSHARE ; ++ DBG_MSG(3, ("UMP Map function: Forcing the CPU to use cache\n")); ++ } ++ /* By setting this flag, during a process fork; the child process will not have the parent UMP mappings */ ++ vma->vm_flags |= VM_DONTCOPY; ++ ++ DBG_MSG(4, ("UMP vma->flags: %x\n", vma->vm_flags )); ++ ++ /* Call the common mmap handler */ ++ err = _ump_ukk_map_mem( &args ); ++ if ( _MALI_OSK_ERR_OK != err) { ++ MSG_ERR(("_ump_ukk_map_mem() failed in function ump_file_mmap()")); ++ return map_errcode( err ); ++ } ++ ++ return 0; /* success */ ++} ++ ++/* Export UMP kernel space API functions */ ++EXPORT_SYMBOL(ump_dd_secure_id_get); ++EXPORT_SYMBOL(ump_dd_handle_create_from_secure_id); ++EXPORT_SYMBOL(ump_dd_phys_block_count_get); ++EXPORT_SYMBOL(ump_dd_phys_block_get); ++EXPORT_SYMBOL(ump_dd_phys_blocks_get); ++EXPORT_SYMBOL(ump_dd_size_get); ++EXPORT_SYMBOL(ump_dd_reference_add); ++EXPORT_SYMBOL(ump_dd_reference_release); ++ ++/* Export our own extended kernel space allocator */ ++EXPORT_SYMBOL(ump_dd_handle_create_from_phys_blocks); ++ ++/* Setup init and exit functions for this module */ ++module_init(ump_initialize_module); ++module_exit(ump_cleanup_module); ++ ++/* And some module informatio */ ++MODULE_LICENSE(UMP_KERNEL_LINUX_LICENSE); ++MODULE_AUTHOR("ARM Ltd."); ++MODULE_VERSION(SVN_REV_STRING); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.h +new file mode 100644 +index 0000000..7c0a17c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_linux.h +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __UMP_KERNEL_LINUX_H__ ++#define __UMP_KERNEL_LINUX_H__ ++ ++int ump_kernel_device_initialize(void); ++void ump_kernel_device_terminate(void); ++ ++ ++#endif /* __UMP_KERNEL_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.c +new file mode 100644 +index 0000000..ca276c8 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.c +@@ -0,0 +1,271 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/* needed to detect kernel version specific code */ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include ++#else /* pre 2.6.26 the file was in the arch specific location */ ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include "ump_kernel_common.h" ++#include "ump_kernel_memory_backend.h" ++ ++ ++ ++#define UMP_BLOCK_SIZE (256UL * 1024UL) /* 256kB, remember to keep the ()s */ ++ ++ ++ ++typedef struct block_info { ++ struct block_info * next; ++} block_info; ++ ++ ++ ++typedef struct block_allocator { ++ struct semaphore mutex; ++ block_info * all_blocks; ++ block_info * first_free; ++ u32 base; ++ u32 num_blocks; ++ u32 num_free; ++} block_allocator; ++ ++ ++static void block_allocator_shutdown(ump_memory_backend * backend); ++static int block_allocator_allocate(void* ctx, ump_dd_mem * mem); ++static void block_allocator_release(void * ctx, ump_dd_mem * handle); ++static inline u32 get_phys(block_allocator * allocator, block_info * block); ++static u32 block_allocator_stat(struct ump_memory_backend *backend); ++ ++ ++ ++/* ++ * Create dedicated memory backend ++ */ ++ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size) ++{ ++ ump_memory_backend * backend; ++ block_allocator * allocator; ++ u32 usable_size; ++ u32 num_blocks; ++ ++ usable_size = (size + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1); ++ num_blocks = usable_size / UMP_BLOCK_SIZE; ++ ++ if (0 == usable_size) { ++ DBG_MSG(1, ("Memory block of size %u is unusable\n", size)); ++ return NULL; ++ } ++ ++ DBG_MSG(5, ("Creating dedicated UMP memory backend. Base address: 0x%08x, size: 0x%08x\n", base_address, size)); ++ DBG_MSG(6, ("%u usable bytes which becomes %u blocks\n", usable_size, num_blocks)); ++ ++ backend = kzalloc(sizeof(ump_memory_backend), GFP_KERNEL); ++ if (NULL != backend) { ++ allocator = kmalloc(sizeof(block_allocator), GFP_KERNEL); ++ if (NULL != allocator) { ++ allocator->all_blocks = kmalloc(sizeof(block_info) * num_blocks, GFP_KERNEL); ++ if (NULL != allocator->all_blocks) { ++ int i; ++ ++ allocator->first_free = NULL; ++ allocator->num_blocks = num_blocks; ++ allocator->num_free = num_blocks; ++ allocator->base = base_address; ++ sema_init(&allocator->mutex, 1); ++ ++ for (i = 0; i < num_blocks; i++) { ++ allocator->all_blocks[i].next = allocator->first_free; ++ allocator->first_free = &allocator->all_blocks[i]; ++ } ++ ++ backend->ctx = allocator; ++ backend->allocate = block_allocator_allocate; ++ backend->release = block_allocator_release; ++ backend->shutdown = block_allocator_shutdown; ++ backend->stat = block_allocator_stat; ++ backend->pre_allocate_physical_check = NULL; ++ backend->adjust_to_mali_phys = NULL; ++ ++ return backend; ++ } ++ kfree(allocator); ++ } ++ kfree(backend); ++ } ++ ++ return NULL; ++} ++ ++ ++ ++/* ++ * Destroy specified dedicated memory backend ++ */ ++static void block_allocator_shutdown(ump_memory_backend * backend) ++{ ++ block_allocator * allocator; ++ ++ BUG_ON(!backend); ++ BUG_ON(!backend->ctx); ++ ++ allocator = (block_allocator*)backend->ctx; ++ ++ DBG_MSG_IF(1, allocator->num_free != allocator->num_blocks, ("%u blocks still in use during shutdown\n", allocator->num_blocks - allocator->num_free)); ++ ++ kfree(allocator->all_blocks); ++ kfree(allocator); ++ kfree(backend); ++} ++ ++ ++ ++static int block_allocator_allocate(void* ctx, ump_dd_mem * mem) ++{ ++ block_allocator * allocator; ++ u32 left; ++ block_info * last_allocated = NULL; ++ int i = 0; ++ ++ BUG_ON(!ctx); ++ BUG_ON(!mem); ++ ++ allocator = (block_allocator*)ctx; ++ left = mem->size_bytes; ++ ++ BUG_ON(!left); ++ BUG_ON(!&allocator->mutex); ++ ++ mem->nr_blocks = ((left + UMP_BLOCK_SIZE - 1) & ~(UMP_BLOCK_SIZE - 1)) / UMP_BLOCK_SIZE; ++ mem->block_array = (ump_dd_physical_block*)vmalloc(sizeof(ump_dd_physical_block) * mem->nr_blocks); ++ if (NULL == mem->block_array) { ++ MSG_ERR(("Failed to allocate block array\n")); ++ return 0; ++ } ++ ++ if (down_interruptible(&allocator->mutex)) { ++ MSG_ERR(("Could not get mutex to do block_allocate\n")); ++ return 0; ++ } ++ ++ mem->size_bytes = 0; ++ ++ while ((left > 0) && (allocator->first_free)) { ++ block_info * block; ++ ++ block = allocator->first_free; ++ allocator->first_free = allocator->first_free->next; ++ block->next = last_allocated; ++ last_allocated = block; ++ allocator->num_free--; ++ ++ mem->block_array[i].addr = get_phys(allocator, block); ++ mem->block_array[i].size = UMP_BLOCK_SIZE; ++ mem->size_bytes += UMP_BLOCK_SIZE; ++ ++ i++; ++ ++ if (left < UMP_BLOCK_SIZE) left = 0; ++ else left -= UMP_BLOCK_SIZE; ++ } ++ ++ if (left) { ++ block_info * block; ++ /* release all memory back to the pool */ ++ while (last_allocated) { ++ block = last_allocated->next; ++ last_allocated->next = allocator->first_free; ++ allocator->first_free = last_allocated; ++ last_allocated = block; ++ allocator->num_free++; ++ } ++ ++ vfree(mem->block_array); ++ mem->backend_info = NULL; ++ mem->block_array = NULL; ++ ++ DBG_MSG(4, ("Could not find a mem-block for the allocation.\n")); ++ up(&allocator->mutex); ++ ++ return 0; ++ } ++ ++ mem->backend_info = last_allocated; ++ ++ up(&allocator->mutex); ++ mem->is_cached=0; ++ ++ return 1; ++} ++ ++ ++ ++static void block_allocator_release(void * ctx, ump_dd_mem * handle) ++{ ++ block_allocator * allocator; ++ block_info * block, * next; ++ ++ BUG_ON(!ctx); ++ BUG_ON(!handle); ++ ++ allocator = (block_allocator*)ctx; ++ block = (block_info*)handle->backend_info; ++ BUG_ON(!block); ++ ++ if (down_interruptible(&allocator->mutex)) { ++ MSG_ERR(("Allocator release: Failed to get mutex - memory leak\n")); ++ return; ++ } ++ ++ while (block) { ++ next = block->next; ++ ++ BUG_ON( (block < allocator->all_blocks) || (block > (allocator->all_blocks + allocator->num_blocks))); ++ ++ block->next = allocator->first_free; ++ allocator->first_free = block; ++ allocator->num_free++; ++ ++ block = next; ++ } ++ DBG_MSG(3, ("%d blocks free after release call\n", allocator->num_free)); ++ up(&allocator->mutex); ++ ++ vfree(handle->block_array); ++ handle->block_array = NULL; ++} ++ ++ ++ ++/* ++ * Helper function for calculating the physical base adderss of a memory block ++ */ ++static inline u32 get_phys(block_allocator * allocator, block_info * block) ++{ ++ return allocator->base + ((block - allocator->all_blocks) * UMP_BLOCK_SIZE); ++} ++ ++static u32 block_allocator_stat(struct ump_memory_backend *backend) ++{ ++ block_allocator *allocator; ++ BUG_ON(!backend); ++ allocator = (block_allocator*)backend->ctx; ++ BUG_ON(!allocator); ++ ++ return (allocator->num_blocks - allocator->num_free)* UMP_BLOCK_SIZE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.h +new file mode 100644 +index 0000000..fa4bdcc +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_dedicated.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2010 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_memory_backend_dedicated.h ++ */ ++ ++#ifndef __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ ++#define __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ ++ ++#include "ump_kernel_memory_backend.h" ++ ++ump_memory_backend * ump_block_allocator_create(u32 base_address, u32 size); ++ ++#endif /* __UMP_KERNEL_MEMORY_BACKEND_DEDICATED_H__ */ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.c +new file mode 100644 +index 0000000..61817c7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.c +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (C) 2010-2011, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/* needed to detect kernel version specific code */ ++#include ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++#include ++#else /* pre 2.6.26 the file was in the arch specific location */ ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ump_kernel_common.h" ++#include "ump_kernel_memory_backend.h" ++ ++ ++ ++typedef struct os_allocator { ++ struct semaphore mutex; ++ u32 num_pages_max; /**< Maximum number of pages to allocate from the OS */ ++ u32 num_pages_allocated; /**< Number of pages allocated from the OS */ ++} os_allocator; ++ ++ ++ ++static void os_free(void* ctx, ump_dd_mem * descriptor); ++static int os_allocate(void* ctx, ump_dd_mem * descriptor); ++static void os_memory_backend_destroy(ump_memory_backend * backend); ++static u32 os_stat(struct ump_memory_backend *backend); ++ ++ ++ ++/* ++ * Create OS memory backend ++ */ ++ump_memory_backend * ump_os_memory_backend_create(const int max_allocation) ++{ ++ ump_memory_backend * backend; ++ os_allocator * info; ++ ++ info = kmalloc(sizeof(os_allocator), GFP_KERNEL); ++ if (NULL == info) { ++ return NULL; ++ } ++ ++ info->num_pages_max = max_allocation >> PAGE_SHIFT; ++ info->num_pages_allocated = 0; ++ ++ sema_init(&info->mutex, 1); ++ ++ backend = kmalloc(sizeof(ump_memory_backend), GFP_KERNEL); ++ if (NULL == backend) { ++ kfree(info); ++ return NULL; ++ } ++ ++ backend->ctx = info; ++ backend->allocate = os_allocate; ++ backend->release = os_free; ++ backend->shutdown = os_memory_backend_destroy; ++ backend->stat = os_stat; ++ backend->pre_allocate_physical_check = NULL; ++ backend->adjust_to_mali_phys = NULL; ++ ++ return backend; ++} ++ ++ ++ ++/* ++ * Destroy specified OS memory backend ++ */ ++static void os_memory_backend_destroy(ump_memory_backend * backend) ++{ ++ os_allocator * info = (os_allocator*)backend->ctx; ++ ++ DBG_MSG_IF(1, 0 != info->num_pages_allocated, ("%d pages still in use during shutdown\n", info->num_pages_allocated)); ++ ++ kfree(info); ++ kfree(backend); ++} ++ ++ ++ ++/* ++ * Allocate UMP memory ++ */ ++static int os_allocate(void* ctx, ump_dd_mem * descriptor) ++{ ++ u32 left; ++ os_allocator * info; ++ int pages_allocated = 0; ++ int is_cached; ++ ++ BUG_ON(!descriptor); ++ BUG_ON(!ctx); ++ ++ info = (os_allocator*)ctx; ++ left = descriptor->size_bytes; ++ is_cached = descriptor->is_cached; ++ ++ if (down_interruptible(&info->mutex)) { ++ DBG_MSG(1, ("Failed to get mutex in os_free\n")); ++ return 0; /* failure */ ++ } ++ ++ descriptor->backend_info = NULL; ++ descriptor->nr_blocks = ((left + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) >> PAGE_SHIFT; ++ ++ DBG_MSG(5, ("Allocating page array. Size: %lu\n", descriptor->nr_blocks * sizeof(ump_dd_physical_block))); ++ ++ descriptor->block_array = (ump_dd_physical_block *)vmalloc(sizeof(ump_dd_physical_block) * descriptor->nr_blocks); ++ if (NULL == descriptor->block_array) { ++ up(&info->mutex); ++ DBG_MSG(1, ("Block array could not be allocated\n")); ++ return 0; /* failure */ ++ } ++ ++ while (left > 0 && ((info->num_pages_allocated + pages_allocated) < info->num_pages_max)) { ++ struct page * new_page; ++ ++ if (is_cached) { ++ new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN); ++ } else { ++ new_page = alloc_page(GFP_HIGHUSER | __GFP_ZERO | __GFP_REPEAT | __GFP_NOWARN | __GFP_COLD); ++ } ++ if (NULL == new_page) { ++ break; ++ } ++ ++ /* Ensure page caches are flushed. */ ++ if ( is_cached ) { ++ descriptor->block_array[pages_allocated].addr = page_to_phys(new_page); ++ descriptor->block_array[pages_allocated].size = PAGE_SIZE; ++ } else { ++ descriptor->block_array[pages_allocated].addr = dma_map_page(NULL, new_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL ); ++ descriptor->block_array[pages_allocated].size = PAGE_SIZE; ++ } ++ ++ DBG_MSG(5, ("Allocated page 0x%08lx cached: %d\n", descriptor->block_array[pages_allocated].addr, is_cached)); ++ ++ if (left < PAGE_SIZE) { ++ left = 0; ++ } else { ++ left -= PAGE_SIZE; ++ } ++ ++ pages_allocated++; ++ } ++ ++ DBG_MSG(5, ("Alloce for ID:%2d got %d pages, cached: %d\n", descriptor->secure_id, pages_allocated)); ++ ++ if (left) { ++ DBG_MSG(1, ("Failed to allocate needed pages\n")); ++ ++ while(pages_allocated) { ++ pages_allocated--; ++ if ( !is_cached ) { ++ dma_unmap_page(NULL, descriptor->block_array[pages_allocated].addr, PAGE_SIZE, DMA_BIDIRECTIONAL); ++ } ++ __free_page(pfn_to_page(descriptor->block_array[pages_allocated].addr >> PAGE_SHIFT) ); ++ } ++ ++ up(&info->mutex); ++ ++ return 0; /* failure */ ++ } ++ ++ info->num_pages_allocated += pages_allocated; ++ ++ DBG_MSG(6, ("%d out of %d pages now allocated\n", info->num_pages_allocated, info->num_pages_max)); ++ ++ up(&info->mutex); ++ ++ return 1; /* success*/ ++} ++ ++ ++/* ++ * Free specified UMP memory ++ */ ++static void os_free(void* ctx, ump_dd_mem * descriptor) ++{ ++ os_allocator * info; ++ int i; ++ ++ BUG_ON(!ctx); ++ BUG_ON(!descriptor); ++ ++ info = (os_allocator*)ctx; ++ ++ BUG_ON(descriptor->nr_blocks > info->num_pages_allocated); ++ ++ if (down_interruptible(&info->mutex)) { ++ DBG_MSG(1, ("Failed to get mutex in os_free\n")); ++ return; ++ } ++ ++ DBG_MSG(5, ("Releasing %lu OS pages\n", descriptor->nr_blocks)); ++ ++ info->num_pages_allocated -= descriptor->nr_blocks; ++ ++ up(&info->mutex); ++ ++ for ( i = 0; i < descriptor->nr_blocks; i++) { ++ DBG_MSG(6, ("Freeing physical page. Address: 0x%08lx\n", descriptor->block_array[i].addr)); ++ if ( ! descriptor->is_cached) { ++ dma_unmap_page(NULL, descriptor->block_array[i].addr, PAGE_SIZE, DMA_BIDIRECTIONAL); ++ } ++ __free_page(pfn_to_page(descriptor->block_array[i].addr>>PAGE_SHIFT) ); ++ } ++ ++ vfree(descriptor->block_array); ++} ++ ++ ++static u32 os_stat(struct ump_memory_backend *backend) ++{ ++ os_allocator *info; ++ info = (os_allocator*)backend->ctx; ++ return info->num_pages_allocated * _MALI_OSK_MALI_PAGE_SIZE; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.h +new file mode 100644 +index 0000000..f924705 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_kernel_memory_backend_os.h +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2010 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_memory_backend_os.h ++ */ ++ ++#ifndef __UMP_KERNEL_MEMORY_BACKEND_OS_H__ ++#define __UMP_KERNEL_MEMORY_BACKEND_OS_H__ ++ ++#include "ump_kernel_memory_backend.h" ++ ++ump_memory_backend * ump_os_memory_backend_create(const int max_allocation); ++ ++#endif /* __UMP_KERNEL_MEMORY_BACKEND_OS_H__ */ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_memory_backend.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_memory_backend.c +new file mode 100644 +index 0000000..e7f84db +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_memory_backend.c +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include /* kernel module definitions */ ++#include /* request_mem_region */ ++ ++#include "arch/config.h" /* Configuration for current platform. The symlink for arch is set by Makefile */ ++ ++#include "ump_osk.h" ++#include "ump_kernel_common.h" ++#include "ump_kernel_memory_backend_os.h" ++#include "ump_kernel_memory_backend_dedicated.h" ++ ++/* Configure which dynamic memory allocator to use */ ++int ump_backend = ARCH_UMP_BACKEND_DEFAULT; ++module_param(ump_backend, int, S_IRUGO); /* r--r--r-- */ ++MODULE_PARM_DESC(ump_backend, "0 = dedicated memory backend (default), 1 = OS memory backend"); ++ ++/* The base address of the memory block for the dedicated memory backend */ ++unsigned int ump_memory_address = ARCH_UMP_MEMORY_ADDRESS_DEFAULT; ++module_param(ump_memory_address, uint, S_IRUGO); /* r--r--r-- */ ++MODULE_PARM_DESC(ump_memory_address, "The physical address to map for the dedicated memory backend"); ++ ++/* The size of the memory block for the dedicated memory backend */ ++unsigned int ump_memory_size = ARCH_UMP_MEMORY_SIZE_DEFAULT; ++module_param(ump_memory_size, uint, S_IRUGO); /* r--r--r-- */ ++MODULE_PARM_DESC(ump_memory_size, "The size of fixed memory to map in the dedicated memory backend"); ++ ++ump_memory_backend* ump_memory_backend_create ( void ) ++{ ++ ump_memory_backend * backend = NULL; ++ ++ /* Create the dynamic memory allocator backend */ ++ if (0 == ump_backend) { ++ DBG_MSG(2, ("Using dedicated memory backend\n")); ++ ++ DBG_MSG(2, ("Requesting dedicated memory: 0x%08x, size: %u\n", ump_memory_address, ump_memory_size)); ++ /* Ask the OS if we can use the specified physical memory */ ++ if (NULL == request_mem_region(ump_memory_address, ump_memory_size, "UMP Memory")) { ++ MSG_ERR(("Failed to request memory region (0x%08X - 0x%08X). Is Mali DD already loaded?\n", ump_memory_address, ump_memory_address + ump_memory_size - 1)); ++ return NULL; ++ } ++ backend = ump_block_allocator_create(ump_memory_address, ump_memory_size); ++ } else if (1 == ump_backend) { ++ DBG_MSG(2, ("Using OS memory backend, allocation limit: %d\n", ump_memory_size)); ++ backend = ump_os_memory_backend_create(ump_memory_size); ++ } ++ ++ return backend; ++} ++ ++void ump_memory_backend_destroy( void ) ++{ ++ if (0 == ump_backend) { ++ DBG_MSG(2, ("Releasing dedicated memory: 0x%08x\n", ump_memory_address)); ++ release_mem_region(ump_memory_address, ump_memory_size); ++ } ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_atomics.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_atomics.c +new file mode 100644 +index 0000000..ef1902e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_atomics.c +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2010 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_osk_atomics.c ++ * Implementation of the OS abstraction layer for the UMP kernel device driver ++ */ ++ ++#include "ump_osk.h" ++#include ++ ++int _ump_osk_atomic_dec_and_read( _mali_osk_atomic_t *atom ) ++{ ++ return atomic_dec_return((atomic_t *)&atom->u.val); ++} ++ ++int _ump_osk_atomic_inc_and_read( _mali_osk_atomic_t *atom ) ++{ ++ return atomic_inc_return((atomic_t *)&atom->u.val); ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_low_level_mem.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_low_level_mem.c +new file mode 100644 +index 0000000..0736c93 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_low_level_mem.c +@@ -0,0 +1,314 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_osk_memory.c ++ * Implementation of the OS abstraction layer for the kernel device driver ++ */ ++ ++/* needed to detect kernel version specific code */ ++#include ++ ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++#include "ump_ukk.h" ++#include "ump_kernel_common.h" ++#include /* kernel module definitions */ ++#include ++#include ++#include ++ ++#include ++#include /* to verify pointers from user space */ ++#include ++#include ++ ++typedef struct ump_vma_usage_tracker { ++ atomic_t references; ++ ump_memory_allocation *descriptor; ++} ump_vma_usage_tracker; ++ ++static void ump_vma_open(struct vm_area_struct * vma); ++static void ump_vma_close(struct vm_area_struct * vma); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++static int ump_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf); ++#else ++static unsigned long ump_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address); ++#endif ++ ++static struct vm_operations_struct ump_vm_ops = { ++ .open = ump_vma_open, ++ .close = ump_vma_close, ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ .fault = ump_cpu_page_fault_handler ++#else ++ .nopfn = ump_cpu_page_fault_handler ++#endif ++}; ++ ++/* ++ * Page fault for VMA region ++ * This should never happen since we always map in the entire virtual memory range. ++ */ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++static int ump_cpu_page_fault_handler(struct vm_area_struct *vma, struct vm_fault *vmf) ++#else ++static unsigned long ump_cpu_page_fault_handler(struct vm_area_struct * vma, unsigned long address) ++#endif ++{ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ void __user * address; ++ address = vmf->virtual_address; ++#endif ++ MSG_ERR(("Page-fault in UMP memory region caused by the CPU\n")); ++ MSG_ERR(("VMA: 0x%08lx, virtual address: 0x%08lx\n", (unsigned long)vma, address)); ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) ++ return VM_FAULT_SIGBUS; ++#else ++ return NOPFN_SIGBUS; ++#endif ++} ++ ++static void ump_vma_open(struct vm_area_struct * vma) ++{ ++ ump_vma_usage_tracker * vma_usage_tracker; ++ int new_val; ++ ++ vma_usage_tracker = (ump_vma_usage_tracker*)vma->vm_private_data; ++ BUG_ON(NULL == vma_usage_tracker); ++ ++ new_val = atomic_inc_return(&vma_usage_tracker->references); ++ ++ DBG_MSG(4, ("VMA open, VMA reference count incremented. VMA: 0x%08lx, reference count: %d\n", (unsigned long)vma, new_val)); ++} ++ ++static void ump_vma_close(struct vm_area_struct * vma) ++{ ++ ump_vma_usage_tracker * vma_usage_tracker; ++ _ump_uk_unmap_mem_s args; ++ int new_val; ++ ++ vma_usage_tracker = (ump_vma_usage_tracker*)vma->vm_private_data; ++ BUG_ON(NULL == vma_usage_tracker); ++ ++ new_val = atomic_dec_return(&vma_usage_tracker->references); ++ ++ DBG_MSG(4, ("VMA close, VMA reference count decremented. VMA: 0x%08lx, reference count: %d\n", (unsigned long)vma, new_val)); ++ ++ if (0 == new_val) { ++ ump_memory_allocation * descriptor; ++ ++ descriptor = vma_usage_tracker->descriptor; ++ ++ args.ctx = descriptor->ump_session; ++ args.cookie = descriptor->cookie; ++ args.mapping = descriptor->mapping; ++ args.size = descriptor->size; ++ ++ args._ukk_private = NULL; /** @note unused */ ++ ++ DBG_MSG(4, ("No more VMA references left, releasing UMP memory\n")); ++ _ump_ukk_unmap_mem( & args ); ++ ++ /* vma_usage_tracker is free()d by _ump_osk_mem_mapregion_term() */ ++ } ++} ++ ++_mali_osk_errcode_t _ump_osk_mem_mapregion_init( ump_memory_allocation * descriptor ) ++{ ++ ump_vma_usage_tracker * vma_usage_tracker; ++ struct vm_area_struct *vma; ++ ++ if (NULL == descriptor) return _MALI_OSK_ERR_FAULT; ++ ++ vma_usage_tracker = kmalloc(sizeof(ump_vma_usage_tracker), GFP_KERNEL); ++ if (NULL == vma_usage_tracker) { ++ DBG_MSG(1, ("Failed to allocate memory for ump_vma_usage_tracker in _mali_osk_mem_mapregion_init\n")); ++ return -_MALI_OSK_ERR_FAULT; ++ } ++ ++ vma = (struct vm_area_struct*)descriptor->process_mapping_info; ++ if (NULL == vma ) { ++ kfree(vma_usage_tracker); ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ vma->vm_private_data = vma_usage_tracker; ++ vma->vm_flags |= VM_IO; ++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) ++ vma->vm_flags |= VM_RESERVED; ++#else ++ vma->vm_flags |= VM_DONTDUMP; ++ vma->vm_flags |= VM_DONTEXPAND; ++ vma->vm_flags |= VM_PFNMAP; ++#endif ++ ++ ++ if (0==descriptor->is_cached) { ++ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); ++ } ++ DBG_MSG(3, ("Mapping with page_prot: 0x%x\n", vma->vm_page_prot )); ++ ++ /* Setup the functions which handle further VMA handling */ ++ vma->vm_ops = &ump_vm_ops; ++ ++ /* Do the va range allocation - in this case, it was done earlier, so we copy in that information */ ++ descriptor->mapping = (void __user*)vma->vm_start; ++ ++ atomic_set(&vma_usage_tracker->references, 1); /*this can later be increased if process is forked, see ump_vma_open() */ ++ vma_usage_tracker->descriptor = descriptor; ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++void _ump_osk_mem_mapregion_term( ump_memory_allocation * descriptor ) ++{ ++ struct vm_area_struct* vma; ++ ump_vma_usage_tracker * vma_usage_tracker; ++ ++ if (NULL == descriptor) return; ++ ++ /* Linux does the right thing as part of munmap to remove the mapping ++ * All that remains is that we remove the vma_usage_tracker setup in init() */ ++ vma = (struct vm_area_struct*)descriptor->process_mapping_info; ++ ++ vma_usage_tracker = vma->vm_private_data; ++ ++ /* We only get called if mem_mapregion_init succeeded */ ++ kfree(vma_usage_tracker); ++ return; ++} ++ ++_mali_osk_errcode_t _ump_osk_mem_mapregion_map( ump_memory_allocation * descriptor, u32 offset, u32 * phys_addr, unsigned long size ) ++{ ++ struct vm_area_struct *vma; ++ _mali_osk_errcode_t retval; ++ ++ if (NULL == descriptor) return _MALI_OSK_ERR_FAULT; ++ ++ vma = (struct vm_area_struct*)descriptor->process_mapping_info; ++ ++ if (NULL == vma ) return _MALI_OSK_ERR_FAULT; ++ ++ retval = remap_pfn_range( vma, ((u32)descriptor->mapping) + offset, (*phys_addr) >> PAGE_SHIFT, size, vma->vm_page_prot) ? _MALI_OSK_ERR_FAULT : _MALI_OSK_ERR_OK;; ++ ++ DBG_MSG(4, ("Mapping virtual to physical memory. ID: %u, vma: 0x%08lx, virtual addr:0x%08lx, physical addr: 0x%08lx, size:%lu, prot:0x%x, vm_flags:0x%x RETVAL: 0x%x\n", ++ ump_dd_secure_id_get(descriptor->handle), ++ (unsigned long)vma, ++ (unsigned long)(vma->vm_start + offset), ++ (unsigned long)*phys_addr, ++ size, ++ (unsigned int)vma->vm_page_prot, vma->vm_flags, retval)); ++ ++ return retval; ++} ++ ++static void level1_cache_flush_all(void) ++{ ++ DBG_MSG(4, ("UMP[xx] Flushing complete L1 cache\n")); ++ __cpuc_flush_kern_all(); ++} ++ ++void _ump_osk_msync( ump_dd_mem * mem, void * virt, u32 offset, u32 size, ump_uk_msync_op op, ump_session_data * session_data ) ++{ ++ int i; ++ ++ /* Flush L1 using virtual address, the entire range in one go. ++ * Only flush if user space process has a valid write mapping on given address. */ ++ if( (mem) && (virt!=NULL) && (access_ok(VERIFY_WRITE, virt, size)) ) { ++ __cpuc_flush_dcache_area(virt, size); ++ DBG_MSG(3, ("UMP[%02u] Flushing CPU L1 Cache. CPU address: %x, size: %x\n", mem->secure_id, virt, size)); ++ } else { ++ if (session_data) { ++ if (op == _UMP_UK_MSYNC_FLUSH_L1 ) { ++ DBG_MSG(4, ("UMP Pending L1 cache flushes: %d\n", session_data->has_pending_level1_cache_flush)); ++ session_data->has_pending_level1_cache_flush = 0; ++ level1_cache_flush_all(); ++ return; ++ } else { ++ if (session_data->cache_operations_ongoing) { ++ session_data->has_pending_level1_cache_flush++; ++ DBG_MSG(4, ("UMP[%02u] Defering the L1 flush. Nr pending:%d\n", mem->secure_id, session_data->has_pending_level1_cache_flush) ); ++ } else { ++ /* Flushing the L1 cache for each switch_user() if ump_cache_operations_control(START) is not called */ ++ level1_cache_flush_all(); ++ } ++ } ++ } else { ++ DBG_MSG(4, ("Unkown state %s %d\n", __FUNCTION__, __LINE__)); ++ level1_cache_flush_all(); ++ } ++ } ++ ++ if ( NULL == mem ) return; ++ ++ if ( mem->size_bytes==size) { ++ DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache\n",mem->secure_id)); ++ } else { ++ DBG_MSG(3, ("UMP[%02u] Flushing CPU L2 Cache. Blocks:%u, TotalSize:%u. FlushSize:%u Offset:0x%x FirstPaddr:0x%08x\n", ++ mem->secure_id, mem->nr_blocks, mem->size_bytes, size, offset, mem->block_array[0].addr)); ++ } ++ ++ ++ /* Flush L2 using physical addresses, block for block. */ ++ for (i=0 ; i < mem->nr_blocks; i++) { ++ u32 start_p, end_p; ++ ump_dd_physical_block *block; ++ block = &mem->block_array[i]; ++ ++ if(offset >= block->size) { ++ offset -= block->size; ++ continue; ++ } ++ ++ if(offset) { ++ start_p = (u32)block->addr + offset; ++ /* We'll zero the offset later, after using it to calculate end_p. */ ++ } else { ++ start_p = (u32)block->addr; ++ } ++ ++ if(size < block->size - offset) { ++ end_p = start_p + size - 1; ++ size = 0; ++ } else { ++ if(offset) { ++ end_p = start_p + (block->size - offset - 1); ++ size -= block->size - offset; ++ offset = 0; ++ } else { ++ end_p = start_p + block->size - 1; ++ size -= block->size; ++ } ++ } ++ ++ switch(op) { ++ case _UMP_UK_MSYNC_CLEAN: ++ outer_clean_range(start_p, end_p); ++ break; ++ case _UMP_UK_MSYNC_CLEAN_AND_INVALIDATE: ++ outer_flush_range(start_p, end_p); ++ break; ++ case _UMP_UK_MSYNC_INVALIDATE: ++ outer_inv_range(start_p, end_p); ++ break; ++ default: ++ break; ++ } ++ ++ if(0 == size) { ++ /* Nothing left to flush. */ ++ break; ++ } ++ } ++ ++ return; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_misc.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_misc.c +new file mode 100644 +index 0000000..ddbce84 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_osk_misc.c +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_osk_misc.c ++ * Implementation of the OS abstraction layer for the UMP kernel device driver ++ */ ++ ++ ++#include "ump_osk.h" ++ ++#include ++#include "ump_kernel_linux.h" ++ ++/* is called from ump_kernel_constructor in common code */ ++_mali_osk_errcode_t _ump_osk_init( void ) ++{ ++ if (0 != ump_kernel_device_initialize()) { ++ return _MALI_OSK_ERR_FAULT; ++ } ++ ++ return _MALI_OSK_ERR_OK; ++} ++ ++_mali_osk_errcode_t _ump_osk_term( void ) ++{ ++ ump_kernel_device_terminate(); ++ return _MALI_OSK_ERR_OK; ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.c +new file mode 100644 +index 0000000..8cbe538 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.c +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_ukk_wrappers.c ++ * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls for the reference implementation ++ */ ++ ++ ++#include /* user space access */ ++ ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++#include "ump_ukk.h" ++#include "ump_kernel_common.h" ++ ++/* ++ * IOCTL operation; Allocate UMP memory ++ */ ++int ump_allocate_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_allocate_s user_interaction; ++ _mali_osk_errcode_t err; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_allocate()\n")); ++ return -ENOTTY; ++ } ++ ++ /* Copy the user space memory to kernel space (so we safely can read it) */ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_allocate()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ err = _ump_ukk_allocate( &user_interaction ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ DBG_MSG(1, ("_ump_ukk_allocate() failed in ump_ioctl_allocate()\n")); ++ return map_errcode(err); ++ } ++ user_interaction.ctx = NULL; ++ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ /* If the copy fails then we should release the memory. We can use the IOCTL release to accomplish this */ ++ _ump_uk_release_s release_args; ++ ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_allocate()\n")); ++ ++ release_args.ctx = (void *) session_data; ++ release_args.secure_id = user_interaction.secure_id; ++ ++ err = _ump_ukk_release( &release_args ); ++ if(_MALI_OSK_ERR_OK != err) { ++ MSG_ERR(("_ump_ukk_release() also failed when trying to release newly allocated memory in ump_ioctl_allocate()\n")); ++ } ++ ++ return -EFAULT; ++ } ++ ++ return 0; /* success */ ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.h +new file mode 100644 +index 0000000..43dabd4 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_ref_wrappers.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_ukk_wrappers.h ++ * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls for the reference implementation ++ */ ++ ++#ifndef __UMP_UKK_REF_WRAPPERS_H__ ++#define __UMP_UKK_REF_WRAPPERS_H__ ++ ++#include ++#include "ump_kernel_common.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++int ump_allocate_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_UKK_REF_WRAPPERS_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.c +new file mode 100644 +index 0000000..6c1831e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.c +@@ -0,0 +1,280 @@ ++/* ++ * Copyright (C) 2010-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_ukk_wrappers.c ++ * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls ++ */ ++ ++#include /* user space access */ ++ ++#include "ump_osk.h" ++#include "ump_uk_types.h" ++#include "ump_ukk.h" ++#include "ump_kernel_common.h" ++ ++/* ++ * IOCTL operation; Negotiate version of IOCTL API ++ */ ++int ump_get_api_version_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_api_version_s version_info; ++ _mali_osk_errcode_t err; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_get_api_version()\n")); ++ return -ENOTTY; ++ } ++ ++ /* Copy the user space memory to kernel space (so we safely can read it) */ ++ if (0 != copy_from_user(&version_info, argument, sizeof(version_info))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_get_api_version()\n")); ++ return -EFAULT; ++ } ++ ++ version_info.ctx = (void*) session_data; ++ err = _ump_uku_get_api_version( &version_info ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ MSG_ERR(("_ump_uku_get_api_version() failed in ump_ioctl_get_api_version()\n")); ++ return map_errcode(err); ++ } ++ ++ version_info.ctx = NULL; ++ ++ /* Copy ouput data back to user space */ ++ if (0 != copy_to_user(argument, &version_info, sizeof(version_info))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_get_api_version()\n")); ++ return -EFAULT; ++ } ++ ++ return 0; /* success */ ++} ++ ++ ++/* ++ * IOCTL operation; Release reference to specified UMP memory. ++ */ ++int ump_release_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_release_s release_args; ++ _mali_osk_errcode_t err; ++ ++ /* Sanity check input parameters */ ++ if (NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_release()\n")); ++ return -ENOTTY; ++ } ++ ++ /* Copy the user space memory to kernel space (so we safely can read it) */ ++ if (0 != copy_from_user(&release_args, argument, sizeof(release_args))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_get_api_version()\n")); ++ return -EFAULT; ++ } ++ ++ release_args.ctx = (void*) session_data; ++ err = _ump_ukk_release( &release_args ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ MSG_ERR(("_ump_ukk_release() failed in ump_ioctl_release()\n")); ++ return map_errcode(err); ++ } ++ ++ ++ return 0; /* success */ ++} ++ ++/* ++ * IOCTL operation; Return size for specified UMP memory. ++ */ ++int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_size_get_s user_interaction; ++ _mali_osk_errcode_t err; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_size_get()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ err = _ump_ukk_size_get( &user_interaction ); ++ if( _MALI_OSK_ERR_OK != err ) { ++ MSG_ERR(("_ump_ukk_size_get() failed in ump_ioctl_size_get()\n")); ++ return map_errcode(err); ++ } ++ ++ user_interaction.ctx = NULL; ++ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_size_get()\n")); ++ return -EFAULT; ++ } ++ ++ return 0; /* success */ ++} ++ ++/* ++ * IOCTL operation; Do cache maintenance on specified UMP memory. ++ */ ++int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_msync_s user_interaction; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_msync()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ _ump_ukk_msync( &user_interaction ); ++ ++ user_interaction.ctx = NULL; ++ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_msync()\n")); ++ return -EFAULT; ++ } ++ ++ return 0; /* success */ ++} ++int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_cache_operations_control_s user_interaction; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_cache_operations_control()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ _ump_ukk_cache_operations_control((_ump_uk_cache_operations_control_s*) &user_interaction ); ++ ++ user_interaction.ctx = NULL; ++ ++#if 0 /* No data to copy back */ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_cache_operations_control()\n")); ++ return -EFAULT; ++ } ++#endif ++ return 0; /* success */ ++} ++ ++int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_switch_hw_usage_s user_interaction; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ _ump_ukk_switch_hw_usage( &user_interaction ); ++ ++ user_interaction.ctx = NULL; ++ ++#if 0 /* No data to copy back */ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++#endif ++ return 0; /* success */ ++} ++ ++int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_lock_s user_interaction; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ _ump_ukk_lock( &user_interaction ); ++ ++ user_interaction.ctx = NULL; ++ ++#if 0 /* No data to copy back */ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++#endif ++ ++ return 0; /* success */ ++} ++ ++int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data) ++{ ++ _ump_uk_unlock_s user_interaction; ++ ++ /* Sanity check input parameters */ ++ if (NULL == argument || NULL == session_data) { ++ MSG_ERR(("NULL parameter in ump_ioctl_size_get()\n")); ++ return -ENOTTY; ++ } ++ ++ if (0 != copy_from_user(&user_interaction, argument, sizeof(user_interaction))) { ++ MSG_ERR(("copy_from_user() in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++ ++ user_interaction.ctx = (void *) session_data; ++ ++ _ump_ukk_unlock( &user_interaction ); ++ ++ user_interaction.ctx = NULL; ++ ++#if 0 /* No data to copy back */ ++ if (0 != copy_to_user(argument, &user_interaction, sizeof(user_interaction))) { ++ MSG_ERR(("copy_to_user() failed in ump_ioctl_switch_hw_usage()\n")); ++ return -EFAULT; ++ } ++#endif ++ ++ return 0; /* success */ ++} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.h +new file mode 100644 +index 0000000..ba76e3d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/linux/ump_ukk_wrappers.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_ukk_wrappers.h ++ * Defines the wrapper functions which turn Linux IOCTL calls into _ukk_ calls ++ */ ++ ++#ifndef __UMP_UKK_WRAPPERS_H__ ++#define __UMP_UKK_WRAPPERS_H__ ++ ++#include ++#include "ump_kernel_common.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++ ++int ump_get_api_version_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_release_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_size_get_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_msync_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_cache_operations_control_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_switch_hw_usage_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_lock_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++int ump_unlock_wrapper(u32 __user * argument, struct ump_session_data * session_data); ++ ++ ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++ ++#endif /* __UMP_UKK_WRAPPERS_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/readme.txt b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/readme.txt +new file mode 100644 +index 0000000..c238cf0 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump/readme.txt +@@ -0,0 +1,28 @@ ++Building the UMP Device Driver for Linux ++---------------------------------------- ++ ++Build the UMP Device Driver for Linux by running the following make command: ++ ++KDIR= CONFIG= BUILD= make ++ ++where ++ kdir_path: Path to your Linux Kernel directory ++ your_config: Name of the sub-folder to find the required config.h file ++ ("arch-" will be prepended) ++ build_option: debug or release. Debug is default. ++ ++The config.h contains following configuration parameters: ++ ++ARCH_UMP_BACKEND_DEFAULT ++ 0 specifies the dedicated memory allocator. ++ 1 specifies the OS memory allocator. ++ARCH_UMP_MEMORY_ADDRESS_DEFAULT ++ This is only required for the dedicated memory allocator, and specifies ++ the physical start address of the memory block reserved for UMP. ++ARCH_UMP_MEMORY_SIZE_DEFAULT ++ This specified the size of the memory block reserved for UMP, or the ++ maximum limit for allocations from the OS. ++ ++The result will be a ump.ko file, which can be loaded into the Linux kernel ++by using the insmod command. The driver can also be built as a part of the ++kernel itself. +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/Makefile b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/Makefile +new file mode 100644 +index 0000000..d1d5c4c +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/Makefile +@@ -0,0 +1,69 @@ ++# ++# Copyright (C) 2012 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++# default to building for the host ++ARCH ?= $(shell uname -m) ++ ++# linux build system integration ++ ++ifneq ($(KERNELRELEASE),) ++# Inside the kernel build system ++ ++EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) ++ ++SRC = umplock_driver.c ++ ++MODULE:=umplock.ko ++ ++obj-m := $(MODULE:.ko=.o) ++$(MODULE:.ko=-y) := $(SRC:.c=.o) ++ ++$(MODULE:.ko=-objs) := $(SRC:.c=.o) ++ ++else ++# Outside the kernel build system ++# ++# ++ ++# Get any user defined KDIR- or maybe even a hardcoded KDIR ++-include KDIR_CONFIGURATION ++ ++# Define host system directory ++KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build ++ ++ifeq ($(ARCH), arm) ++ # when compiling for ARM we're cross compiling ++ export CROSS_COMPILE ?= arm-none-linux-gnueabi- ++ CONFIG ?= arm ++else ++ # Compiling for the host ++ CONFIG ?= $(shell uname -m) ++endif ++ ++# default cpu to select ++CPU ?= $(shell uname -m) ++ ++# look up KDIR based om CPU selection ++KDIR ?= $(KDIR-$(CPU)) ++ ++ifeq ($(KDIR),) ++$(error No KDIR found for platform $(CPU)) ++endif ++ ++all: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) ++ ++kernelrelease: ++ $(MAKE) -C $(KDIR) kernelrelease ++ ++clean: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean ++ ++endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_driver.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_driver.c +new file mode 100644 +index 0000000..bd537b3 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_driver.c +@@ -0,0 +1,598 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "umplock_ioctl.h" ++#include ++ ++#define MAX_ITEMS 1024 ++#define MAX_PIDS 128 ++ ++typedef struct lock_cmd_priv { ++ uint32_t msg[128]; /*ioctl args*/ ++ u32 pid; /*process id*/ ++} _lock_cmd_priv; ++ ++typedef struct lock_ref { ++ int ref_count; ++ u32 pid; ++} _lock_ref; ++ ++typedef struct umplock_item { ++ u32 secure_id; ++ /*u32 references;*/ ++ _lock_access_usage usage; ++ _lock_ref references[MAX_PIDS]; ++ struct semaphore item_lock; ++} umplock_item; ++ ++typedef struct umplock_device_private { ++ struct mutex item_list_lock; ++ atomic_t sessions; ++ umplock_item items[MAX_ITEMS]; ++ u32 pids[MAX_PIDS]; ++} umplock_device_private; ++ ++struct umplock_device { ++ struct cdev cdev; ++ struct class *umplock_class; ++}; ++ ++static char umplock_dev_name[] = "umplock"; ++ ++int umplock_major = 0; ++module_param(umplock_major, int, S_IRUGO); /* r--r--r-- */ ++MODULE_PARM_DESC(umplock_major, "Device major number"); ++ ++static int umplock_driver_open( struct inode *inode, struct file *filp ); ++static int umplock_driver_release( struct inode *inode, struct file *filp ); ++static long umplock_driver_ioctl( struct file *f, unsigned int cmd, unsigned long arg ); ++ ++static struct file_operations umplock_fops = { ++ .owner = THIS_MODULE, ++ .open = umplock_driver_open, ++ .release = umplock_driver_release, ++ .unlocked_ioctl = umplock_driver_ioctl, ++}; ++ ++static struct umplock_device umplock_device; ++static umplock_device_private device; ++ ++void umplock_init_locklist( void ) ++{ ++ memset(&device.items, 0, sizeof(umplock_item)*MAX_ITEMS); ++ atomic_set(&device.sessions, 0); ++} ++ ++void umplock_deinit_locklist( void ) ++{ ++ memset(&device.items, 0, sizeof(umplock_item)*MAX_ITEMS); ++} ++ ++int umplock_device_initialize( void ) ++{ ++ int err; ++ dev_t dev = 0; ++ ++ if ( 0 == umplock_major ) { ++ err = alloc_chrdev_region(&dev, 0, 1, umplock_dev_name); ++ umplock_major = MAJOR(dev); ++ } else { ++ dev = MKDEV(umplock_major, 0); ++ err = register_chrdev_region(dev, 1, umplock_dev_name); ++ } ++ ++ if ( 0 == err ) { ++ memset(&umplock_device, 0, sizeof(umplock_device)); ++ cdev_init(&umplock_device.cdev, &umplock_fops); ++ umplock_device.cdev.owner = THIS_MODULE; ++ umplock_device.cdev.ops = &umplock_fops; ++ ++ err = cdev_add(&umplock_device.cdev, dev, 1); ++ if ( 0 == err ) { ++ umplock_device.umplock_class = class_create(THIS_MODULE, umplock_dev_name); ++ if ( IS_ERR(umplock_device.umplock_class ) ) { ++ err = PTR_ERR(umplock_device.umplock_class); ++ } else { ++ struct device *mdev; ++ mdev = device_create(umplock_device.umplock_class, NULL, dev, NULL, umplock_dev_name); ++ if ( !IS_ERR(mdev) ) { ++ return 0; /* all ok */ ++ } ++ ++ err = PTR_ERR(mdev); ++ class_destroy(umplock_device.umplock_class); ++ } ++ cdev_del(&umplock_device.cdev); ++ } ++ ++ unregister_chrdev_region(dev, 1); ++ } ++ ++ return 1; ++} ++ ++void umplock_device_terminate(void) ++{ ++ dev_t dev = MKDEV(umplock_major, 0); ++ ++ device_destroy(umplock_device.umplock_class, dev); ++ class_destroy(umplock_device.umplock_class); ++ ++ cdev_del(&umplock_device.cdev); ++ unregister_chrdev_region(dev, 1); ++} ++ ++int umplock_constructor(void) ++{ ++ mutex_init(&device.item_list_lock); ++ if ( !umplock_device_initialize() ) return 1; ++ umplock_init_locklist(); ++ ++ return 0; ++} ++ ++void umplock_destructor(void) ++{ ++ umplock_deinit_locklist(); ++ umplock_device_terminate(); ++ mutex_destroy(&device.item_list_lock); ++} ++ ++int umplock_find_item( u32 secure_id ) ++{ ++ int i; ++ for ( i=0; imsg; ++ ++ i = umplock_find_item(lock_item->secure_id); ++ ++ if ( i < 0) ++ return -1; ++ ++ for(j=0; jpid) { ++ *item_slot = i; ++ *ref_slot = j; ++ return 0; ++ } ++ } ++ return -1 ; ++} ++ ++static int umplock_find_client_valid(u32 pid) ++{ ++ int i; ++ ++ if(pid == 0) ++ return -1; ++ ++ for(i=0; imsg; ++ ++ i_index = ref_index = -1; ++ ++#if 0 ++ if ( lock_item->usage == 1 ) printk( KERN_DEBUG "UMPLOCK: C 0x%x GPU SURFACE\n", lock_item->secure_id ); ++ else if ( lock_item->usage == 2 ) printk( KERN_DEBUG "UMPLOCK: C 0x%x GPU TEXTURE\n", lock_item->secure_id ); ++ else printk( KERN_DEBUG "UMPLOCK: C 0x%x CPU\n", lock_item->secure_id ); ++#endif ++ ++ ret = umplock_find_client_valid( lock_cmd->pid ); ++ if( ret < 0 ) { ++ /*lock request from an invalid client pid, do nothing*/ ++ return 0; ++ } ++ ++ ret = umplock_find_item_by_pid( lock_cmd, &i_index, &ref_index ); ++ if ( ret >= 0 ) { ++ if (device.items[i_index].references[ref_index].ref_count == 0) ++ device.items[i_index].references[ref_index].ref_count = 1; ++ } else if ( (i_index = umplock_find_item( lock_item->secure_id)) >= 0 ) { ++ for ( ref_index = 0; ref_index < MAX_PIDS; ref_index++) { ++ if (device.items[i_index].references[ref_index].pid == 0) break; ++ } ++ if ( ref_index < MAX_PIDS ) { ++ device.items[i_index].references[ref_index].pid = lock_cmd->pid; ++ device.items[i_index].references[ref_index].ref_count = 1; ++ } else { ++ printk( KERN_ERR "UMPLOCK: whoops, item ran out of available reference slot\n" ); ++ } ++ } else { ++ i_index = umplock_find_slot(); ++ ++ if ( i_index >= 0 ) { ++ device.items[i_index].secure_id = lock_item->secure_id; ++ device.items[i_index].usage = lock_item->usage; ++ device.items[i_index].references[0].pid = lock_cmd->pid; ++ device.items[i_index].references[0].ref_count = 1; ++ sema_init(&device.items[i_index].item_lock, 1); ++ } else { ++ printk( KERN_ERR "UMPLOCK: whoops, ran out of available slots\n" ); ++ } ++ } ++ ++ return 0; ++} ++/** IOCTLs **/ ++ ++static int do_umplock_create(_lock_cmd_priv *lock_cmd) ++{ ++ int ret = 0; ++ mutex_lock(&device.item_list_lock); ++ ret = do_umplock_create_locked(lock_cmd); ++ mutex_unlock(&device.item_list_lock); ++ return ret; ++} ++ ++static int do_umplock_process( _lock_cmd_priv *lock_cmd ) ++{ ++ int ret, i_index, ref_index, ref_count; ++ _lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg; ++ ++ mutex_lock(&device.item_list_lock); ++ ++ do_umplock_create_locked(lock_cmd); ++ ++ ret = umplock_find_client_valid( lock_cmd->pid ); ++ if( ret < 0 ) { ++ /*lock request from an invalid client pid, do nothing*/ ++ mutex_unlock(&device.item_list_lock); ++ return 0; ++ } ++ ++ ret = umplock_find_item_by_pid( lock_cmd, &i_index, &ref_index ); ++ ref_count = device.items[i_index].references[ref_index].ref_count; ++ if ( ret >= 0 ) { ++ if (ref_count == 1) { ++ /*add ref before down to wait for the umplock*/ ++ device.items[i_index].references[ref_index].ref_count++; ++ mutex_unlock(&device.item_list_lock); ++ if ( down_interruptible(&device.items[i_index].item_lock) ) { ++ /*wait up without hold the umplock. restore previous state and return*/ ++ mutex_lock(&device.item_list_lock); ++ device.items[i_index].references[ref_index].ref_count--; ++ mutex_unlock(&device.item_list_lock); ++ return -ERESTARTSYS; ++ } ++ mutex_lock(&device.item_list_lock); ++ } else { ++ /*already got the umplock, add ref*/ ++ device.items[i_index].references[ref_index].ref_count++; ++ } ++#if 0 ++ if ( lock_item->usage == 1 ) printk( KERN_DEBUG "UMPLOCK: P 0x%x GPU SURFACE\n", lock_item->secure_id ); ++ else if ( lock_item->usage == 2 ) printk( KERN_DEBUG "UMPLOCK: P 0x%x GPU TEXTURE\n", lock_item->secure_id ); ++ else printk( KERN_DEBUG "UMPLOCK: P 0x%x CPU\n", lock_item->secure_id ); ++#endif ++ } else { ++ /*fail to find a item*/ ++ printk(KERN_ERR "UMPLOCK: IOCTL_UMPLOCK_PROCESS called with invalid parameter\n"); ++ mutex_unlock(&device.item_list_lock); ++ return -EINVAL; ++ } ++ mutex_unlock(&device.item_list_lock); ++ return 0; ++} ++ ++static int do_umplock_release( _lock_cmd_priv *lock_cmd ) ++{ ++ int i_index,ref_index, ref_count; ++ int ret; ++ _lock_item_s *lock_item = (_lock_item_s *)&lock_cmd->msg; ++ ++ mutex_lock(&device.item_list_lock); ++ ret = umplock_find_client_valid( lock_cmd->pid ); ++ if( ret < 0 ) { ++ /*lock request from an invalid client pid, do nothing*/ ++ mutex_unlock(&device.item_list_lock); ++ return 0; ++ } ++ ++ i_index = ref_index = -1; ++ ++ ret = umplock_find_item_by_pid( lock_cmd, &i_index, &ref_index ); ++ ++ if ( ret >= 0 ) { ++ device.items[i_index].references[ref_index].ref_count--; ++ ref_count = device.items[i_index].references[ref_index].ref_count; ++ ++#if 0 ++ if ( lock_item->usage == 1 ) printk( KERN_DEBUG "UMPLOCK: R 0x%x GPU SURFACE\n", lock_item->secure_id ); ++ else if ( lock_item->usage == 2 ) printk( KERN_DEBUG "UMPLOCK: R 0x%x GPU TEXTURE\n", lock_item->secure_id ); ++ else printk( KERN_DEBUG "UMPLOCK: R 0x%x CPU\n", lock_item->secure_id ); ++#endif ++ /*reached the last reference to the umplock*/ ++ if ( ref_count == 1 ) { ++ /*release the umplock*/ ++ up( &device.items[i_index].item_lock ); ++ ++ device.items[i_index].references[ref_index].ref_count = 0; ++ device.items[i_index].references[ref_index].pid = 0; ++ } ++ } else { ++ /*fail to find item*/ ++ printk(KERN_ERR "UMPLOCK: IOCTL_UMPLOCK_RELEASE called with invalid parameter\n"); ++ mutex_unlock(&device.item_list_lock); ++ return -EINVAL; ++ } ++ mutex_unlock(&device.item_list_lock); ++ return 0; ++} ++ ++static int do_umplock_zap( void ) ++{ ++ int i; ++ ++ printk( KERN_DEBUG "UMPLOCK: ZAP ALL ENTRIES!\n" ); ++ ++ mutex_lock(&device.item_list_lock); ++ ++ for ( i=0; isecure_id=%d\t reference[%d].ref_count=%d.pid=%d\n", ++ i, ++ device.items[i].secure_id, ++ j, ++ device.items[i].references[j].ref_count, ++ device.items[i].references[j].pid); ++ } ++ } ++ } ++ mutex_unlock(&device.item_list_lock); ++ ++ return 0; ++} ++ ++int do_umplock_client_add (_lock_cmd_priv *lock_cmd ) ++{ ++ int i; ++ mutex_lock(&device.item_list_lock); ++ for ( i= 0; ipid) { ++ return 0; ++ } ++ } ++ for ( i=0; ipid; ++ break; ++ } ++ } ++ mutex_unlock(&device.item_list_lock); ++ if( i==MAX_PIDS) { ++ printk(KERN_ERR "Oops, Run out of cient slots\n "); ++ } ++ return 0; ++} ++ ++int do_umplock_client_delete (_lock_cmd_priv *lock_cmd ) ++{ ++ int p_index=-1, i_index=-1,ref_index=-1; ++ int ret; ++ _lock_item_s *lock_item; ++ lock_item = (_lock_item_s *)&lock_cmd->msg; ++ ++ mutex_lock(&device.item_list_lock); ++ p_index = umplock_find_client_valid( lock_cmd->pid ); ++ /*lock item pid is not valid.*/ ++ if ( p_index<0 ) { ++ mutex_unlock(&device.item_list_lock); ++ return 0; ++ } ++ ++ /*walk through umplock item list and release reference attached to this client*/ ++ for(i_index = 0; i_index< MAX_ITEMS; i_index++ ) { ++ lock_item->secure_id = device.items[i_index].secure_id; ++ /*find the item index and reference slot for the lock_item*/ ++ ret = umplock_find_item_by_pid(lock_cmd, &i_index, &ref_index); ++ ++ if(ret < 0) { ++ /*client has no reference on this umplock item, skip*/ ++ continue; ++ } ++ while(device.items[i_index].references[ref_index].ref_count) { ++ /*release references on this client*/ ++ mutex_unlock(&device.item_list_lock); ++ do_umplock_release(lock_cmd); ++ mutex_lock(&device.item_list_lock); ++ } ++ } ++ ++ /*remove the pid from umplock valid pid list*/ ++ device.pids[p_index] = 0; ++ mutex_unlock(&device.item_list_lock); ++ ++ return 0; ++} ++ ++static long umplock_driver_ioctl( struct file *f, unsigned int cmd, unsigned long arg ) ++{ ++ int ret; ++ uint32_t size = _IOC_SIZE(cmd); ++ _lock_cmd_priv lock_cmd ; ++ ++ if (_IOC_TYPE(cmd) != LOCK_IOCTL_GROUP ) { ++ return -ENOTTY; ++ } ++ ++ if (_IOC_NR(cmd) >= LOCK_IOCTL_MAX_CMDS ) { ++ return -ENOTTY; ++ } ++ ++ switch ( cmd ) { ++ case LOCK_IOCTL_CREATE: ++ if (size != sizeof(_lock_item_s)) { ++ return -ENOTTY; ++ } ++ ++ if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) { ++ return -EFAULT; ++ } ++ lock_cmd.pid = (u32)current->tgid; ++ ret = do_umplock_create(&lock_cmd); ++ if (ret) { ++ return ret; ++ } ++ return 0; ++ ++ case LOCK_IOCTL_PROCESS: ++ if (size != sizeof(_lock_item_s)) { ++ return -ENOTTY; ++ } ++ ++ if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) { ++ return -EFAULT; ++ } ++ lock_cmd.pid = (u32)current->tgid; ++ return do_umplock_process(&lock_cmd); ++ ++ case LOCK_IOCTL_RELEASE: ++ if (size != sizeof(_lock_item_s)) { ++ return -ENOTTY; ++ } ++ ++ if (copy_from_user(&lock_cmd.msg, (void __user *)arg, size)) { ++ return -EFAULT; ++ } ++ lock_cmd.pid = (u32)current->tgid; ++ ret = do_umplock_release( &lock_cmd ); ++ if (ret) { ++ return ret; ++ } ++ return 0; ++ ++ case LOCK_IOCTL_ZAP: ++ do_umplock_zap(); ++ return 0; ++ ++ case LOCK_IOCTL_DUMP: ++ do_umplock_dump(); ++ return 0; ++ } ++ ++ return -ENOIOCTLCMD; ++} ++ ++static int umplock_driver_open( struct inode *inode, struct file *filp ) ++{ ++ _lock_cmd_priv lock_cmd; ++ ++ atomic_inc(&device.sessions); ++ printk( KERN_DEBUG "UMPLOCK: OPEN SESSION (%i references)\n", atomic_read(&device.sessions) ); ++ ++ lock_cmd.pid = (u32)current->tgid; ++ do_umplock_client_add(&lock_cmd); ++ ++ return 0; ++} ++ ++static int umplock_driver_release( struct inode *inode, struct file *filp ) ++{ ++ _lock_cmd_priv lock_cmd; ++ ++ lock_cmd.pid = (u32)current->tgid; ++ do_umplock_client_delete(&lock_cmd); ++ ++ atomic_dec(&device.sessions); ++ printk( KERN_DEBUG "UMPLOCK: CLOSE SESSION (%i references)\n", atomic_read(&device.sessions) ); ++ if ( atomic_read(&device.sessions) == 0 ) { ++ do_umplock_zap(); ++ } ++ ++ return 0; ++} ++ ++static int __init umplock_initialize_module( void ) ++{ ++ printk( KERN_DEBUG "Inserting UMP lock device driver. Compiled: %s, time: %s\n", __DATE__, __TIME__ ); ++ ++ if ( !umplock_constructor() ) { ++ printk( KERN_ERR "UMP lock device driver init failed\n"); ++ return -ENOTTY; ++ } ++ ++ printk( KERN_DEBUG "UMP lock device driver loaded\n" ); ++ ++ return 0; ++} ++ ++static void __exit umplock_cleanup_module( void ) ++{ ++ printk( KERN_DEBUG "unloading UMP lock module\n" ); ++ umplock_destructor(); ++ printk( KERN_DEBUG "UMP lock module unloaded\n" ); ++} ++ ++module_init(umplock_initialize_module); ++module_exit(umplock_cleanup_module); ++ ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("ARM Ltd."); ++MODULE_DESCRIPTION("ARM UMP locker"); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_ioctl.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_ioctl.h +new file mode 100644 +index 0000000..88b0a46 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/umplock/umplock_ioctl.h +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __UMPLOCK_IOCTL_H__ ++#define __UMPLOCK_IOCTL_H__ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++#include ++ ++#ifndef __user ++#define __user ++#endif ++ ++ ++/** ++ * @file umplock_ioctl.h ++ * This file describes the interface needed to use the Linux device driver. ++ * The interface is used by the userpace Mali DDK. ++ */ ++ ++typedef enum { ++ _LOCK_ACCESS_RENDERABLE = 1, ++ _LOCK_ACCESS_TEXTURE, ++ _LOCK_ACCESS_CPU_WRITE, ++ _LOCK_ACCESS_CPU_READ, ++} _lock_access_usage; ++ ++typedef struct _lock_item_s { ++ unsigned int secure_id; ++ _lock_access_usage usage; ++} _lock_item_s; ++ ++ ++#define LOCK_IOCTL_GROUP 0x91 ++ ++#define _LOCK_IOCTL_CREATE_CMD 0 /* create kernel lock item */ ++#define _LOCK_IOCTL_PROCESS_CMD 1 /* process kernel lock item */ ++#define _LOCK_IOCTL_RELEASE_CMD 2 /* release kernel lock item */ ++#define _LOCK_IOCTL_ZAP_CMD 3 /* clean up all kernel lock items */ ++#define _LOCK_IOCTL_DUMP_CMD 4 /* dump all the items */ ++ ++#define LOCK_IOCTL_MAX_CMDS 5 ++ ++#define LOCK_IOCTL_CREATE _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_CREATE_CMD, _lock_item_s ) ++#define LOCK_IOCTL_PROCESS _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_PROCESS_CMD, _lock_item_s ) ++#define LOCK_IOCTL_RELEASE _IOW( LOCK_IOCTL_GROUP, _LOCK_IOCTL_RELEASE_CMD, _lock_item_s ) ++#define LOCK_IOCTL_ZAP _IO ( LOCK_IOCTL_GROUP, _LOCK_IOCTL_ZAP_CMD ) ++#define LOCK_IOCTL_DUMP _IO ( LOCK_IOCTL_GROUP, _LOCK_IOCTL_DUMP_CMD ) ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMPLOCK_IOCTL_H__ */ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/Makefile b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/Makefile +new file mode 100644 +index 0000000..580defc +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/Makefile +@@ -0,0 +1,78 @@ ++# ++# Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++ ++MALI_DRM_FILE_PREFIX = ++ ++# For each arch check: CROSS_COMPILE , KDIR , CFLAGS += -DARCH ++ ++ARCH ?= arm ++## @note Should allow overriding of building MALI DRM for non-debug: ++EXTRA_CFLAGS += -DDEBUG ++ ++DRM_SYMVERS_FILE = ../drm/Module.symvers ++KBUILD_EXTRA_SYMBOLS = $(KBUILD_EXTMOD)/$(DRM_SYMVERS_FILE) ++ ++ ++# linux build system integration ++ ++ifneq ($(KERNELRELEASE),) ++# Inside the kernel build system ++ ++#EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/../drm/include/ ++EXTRA_CFLAGS += -I$(KBUILD_EXTMOD) -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/../drm/include/ -D__linux__ ++ ++SRC += $(MALI_DRM_FILE_PREFIX)mali/mali_drv.c \ ++ $(MALI_DRM_FILE_PREFIX)mali/mali_mm.c ++ ++# Selecting files to compile by parsing the config file ++ ++MODULE:=mali_drm.ko ++ ++obj-m := $(MODULE:.ko=.o) ++$(MODULE:.ko=-y) := $(SRC:.c=.o) ++ ++else ++# Outside the kernel build system ++ ++# Get any user defined KDIR- or maybe even a hardcoded KDIR ++-include KDIR_CONFIGURATION ++ ++# Define host system directory ++KDIR-$(shell uname -m):=/lib/modules/$(shell uname -r)/build ++ ++ifeq ($(ARCH), arm) ++ # when compiling for ARM we're cross compiling ++ export CROSS_COMPILE ?= arm-none-linux-gnueabi- ++ # default to Virtex5 ++ CONFIG ?= pb-virtex5 ++else ++ # Compiling for the host ++ CONFIG ?= $(shell uname -m) ++endif ++ ++# default cpu to select ++CPU ?= ct11mp ++ ++# look up KDIR based om CPU selection ++KDIR ?= $(KDIR-$(CPU)) ++ifeq ($(KDIR),) ++$(error No KDIR found for platform $(CPU)) ++endif ++ ++all: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) modules ++ ++kernelrelease: ++ $(MAKE) -C $(KDIR) kernelrelease ++ ++clean: ++ $(MAKE) ARCH=$(ARCH) -C $(KDIR) M=$(CURDIR) clean ++ ++endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/Kbuild b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/Kbuild +new file mode 100644 +index 0000000..c921ab1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/Kbuild +@@ -0,0 +1,11 @@ ++unifdef-y += drm.h drm_sarea.h ++unifdef-y += i810_drm.h ++unifdef-y += i830_drm.h ++unifdef-y += i915_drm.h ++unifdef-y += mga_drm.h ++unifdef-y += r128_drm.h ++unifdef-y += radeon_drm.h ++unifdef-y += sis_drm.h ++unifdef-y += savage_drm.h ++unifdef-y += via_drm.h ++unifdef-y += mali_drm.h +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm.h +new file mode 100644 +index 0000000..64ff02d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm.h +@@ -0,0 +1,824 @@ ++/** ++ * \file drm.h ++ * Header for the Direct Rendering Manager ++ * ++ * \author Rickard E. (Rik) Faith ++ * ++ * \par Acknowledgments: ++ * Dec 1999, Richard Henderson , move to generic \c cmpxchg. ++ */ ++ ++/* ++ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _DRM_H_ ++#define _DRM_H_ ++ ++#if defined(__linux__) ++ ++#include ++#include ++typedef unsigned int drm_handle_t; ++ ++#else /* One of the BSDs */ ++ ++#include ++#include ++typedef int8_t __s8; ++typedef uint8_t __u8; ++typedef int16_t __s16; ++typedef uint16_t __u16; ++typedef int32_t __s32; ++typedef uint32_t __u32; ++typedef int64_t __s64; ++typedef uint64_t __u64; ++typedef unsigned long drm_handle_t; ++ ++#endif ++ ++#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ ++#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ ++#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ ++#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ ++ ++#define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ ++#define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */ ++#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) ++#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) ++#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) ++ ++typedef unsigned int drm_context_t; ++typedef unsigned int drm_drawable_t; ++typedef unsigned int drm_magic_t; ++ ++/** ++ * Cliprect. ++ * ++ * \warning: If you change this structure, make sure you change ++ * XF86DRIClipRectRec in the server as well ++ * ++ * \note KW: Actually it's illegal to change either for ++ * backwards-compatibility reasons. ++ */ ++struct drm_clip_rect { ++ unsigned short x1; ++ unsigned short y1; ++ unsigned short x2; ++ unsigned short y2; ++}; ++ ++/** ++ * Drawable information. ++ */ ++struct drm_drawable_info { ++ unsigned int num_rects; ++ struct drm_clip_rect *rects; ++}; ++ ++/** ++ * Texture region, ++ */ ++struct drm_tex_region { ++ unsigned char next; ++ unsigned char prev; ++ unsigned char in_use; ++ unsigned char padding; ++ unsigned int age; ++}; ++ ++/** ++ * Hardware lock. ++ * ++ * The lock structure is a simple cache-line aligned integer. To avoid ++ * processor bus contention on a multiprocessor system, there should not be any ++ * other data stored in the same cache line. ++ */ ++struct drm_hw_lock { ++ __volatile__ unsigned int lock; /**< lock variable */ ++ char padding[60]; /**< Pad to cache line */ ++}; ++ ++/** ++ * DRM_IOCTL_VERSION ioctl argument type. ++ * ++ * \sa drmGetVersion(). ++ */ ++struct drm_version { ++ int version_major; /**< Major version */ ++ int version_minor; /**< Minor version */ ++ int version_patchlevel; /**< Patch level */ ++ size_t name_len; /**< Length of name buffer */ ++ char __user *name; /**< Name of driver */ ++ size_t date_len; /**< Length of date buffer */ ++ char __user *date; /**< User-space buffer to hold date */ ++ size_t desc_len; /**< Length of desc buffer */ ++ char __user *desc; /**< User-space buffer to hold desc */ ++}; ++ ++/** ++ * DRM_IOCTL_GET_UNIQUE ioctl argument type. ++ * ++ * \sa drmGetBusid() and drmSetBusId(). ++ */ ++struct drm_unique { ++ size_t unique_len; /**< Length of unique */ ++ char __user *unique; /**< Unique name for driver instantiation */ ++}; ++ ++struct drm_list { ++ int count; /**< Length of user-space structures */ ++ struct drm_version __user *version; ++}; ++ ++struct drm_block { ++ int unused; ++}; ++ ++/** ++ * DRM_IOCTL_CONTROL ioctl argument type. ++ * ++ * \sa drmCtlInstHandler() and drmCtlUninstHandler(). ++ */ ++struct drm_control { ++ enum { ++ DRM_ADD_COMMAND, ++ DRM_RM_COMMAND, ++ DRM_INST_HANDLER, ++ DRM_UNINST_HANDLER ++ } func; ++ int irq; ++}; ++ ++/** ++ * Type of memory to map. ++ */ ++enum drm_map_type { ++ _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */ ++ _DRM_REGISTERS = 1, /**< no caching, no core dump */ ++ _DRM_SHM = 2, /**< shared, cached */ ++ _DRM_AGP = 3, /**< AGP/GART */ ++ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ ++ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ ++ _DRM_GEM = 6, /**< GEM object */ ++}; ++ ++/** ++ * Memory mapping flags. ++ */ ++enum drm_map_flags { ++ _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */ ++ _DRM_READ_ONLY = 0x02, ++ _DRM_LOCKED = 0x04, /**< shared, cached, locked */ ++ _DRM_KERNEL = 0x08, /**< kernel requires access */ ++ _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ ++ _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ ++ _DRM_REMOVABLE = 0x40, /**< Removable mapping */ ++ _DRM_DRIVER = 0x80 /**< Managed by driver */ ++}; ++ ++struct drm_ctx_priv_map { ++ unsigned int ctx_id; /**< Context requesting private mapping */ ++ void *handle; /**< Handle of map */ ++}; ++ ++/** ++ * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls ++ * argument type. ++ * ++ * \sa drmAddMap(). ++ */ ++struct drm_map { ++ unsigned long offset; /**< Requested physical address (0 for SAREA)*/ ++ unsigned long size; /**< Requested physical size (bytes) */ ++ enum drm_map_type type; /**< Type of memory to map */ ++ enum drm_map_flags flags; /**< Flags */ ++ void *handle; /**< User-space: "Handle" to pass to mmap() */ ++ /**< Kernel-space: kernel-virtual address */ ++ int mtrr; /**< MTRR slot used */ ++ /* Private data */ ++}; ++ ++/** ++ * DRM_IOCTL_GET_CLIENT ioctl argument type. ++ */ ++struct drm_client { ++ int idx; /**< Which client desired? */ ++ int auth; /**< Is client authenticated? */ ++ unsigned long pid; /**< Process ID */ ++ unsigned long uid; /**< User ID */ ++ unsigned long magic; /**< Magic */ ++ unsigned long iocs; /**< Ioctl count */ ++}; ++ ++enum drm_stat_type { ++ _DRM_STAT_LOCK, ++ _DRM_STAT_OPENS, ++ _DRM_STAT_CLOSES, ++ _DRM_STAT_IOCTLS, ++ _DRM_STAT_LOCKS, ++ _DRM_STAT_UNLOCKS, ++ _DRM_STAT_VALUE, /**< Generic value */ ++ _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */ ++ _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */ ++ ++ _DRM_STAT_IRQ, /**< IRQ */ ++ _DRM_STAT_PRIMARY, /**< Primary DMA bytes */ ++ _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */ ++ _DRM_STAT_DMA, /**< DMA */ ++ _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */ ++ _DRM_STAT_MISSED /**< Missed DMA opportunity */ ++ /* Add to the *END* of the list */ ++}; ++ ++/** ++ * DRM_IOCTL_GET_STATS ioctl argument type. ++ */ ++struct drm_stats { ++ unsigned long count; ++ struct { ++ unsigned long value; ++ enum drm_stat_type type; ++ } data[15]; ++}; ++ ++/** ++ * Hardware locking flags. ++ */ ++enum drm_lock_flags { ++ _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ ++ _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ ++ _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ ++ _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ ++ /* These *HALT* flags aren't supported yet ++ -- they will be used to support the ++ full-screen DGA-like mode. */ ++ _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ ++ _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ ++}; ++ ++/** ++ * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type. ++ * ++ * \sa drmGetLock() and drmUnlock(). ++ */ ++struct drm_lock { ++ int context; ++ enum drm_lock_flags flags; ++}; ++ ++/** ++ * DMA flags ++ * ++ * \warning ++ * These values \e must match xf86drm.h. ++ * ++ * \sa drm_dma. ++ */ ++enum drm_dma_flags { ++ /* Flags for DMA buffer dispatch */ ++ _DRM_DMA_BLOCK = 0x01, /**< ++ * Block until buffer dispatched. ++ * ++ * \note The buffer may not yet have ++ * been processed by the hardware -- ++ * getting a hardware lock with the ++ * hardware quiescent will ensure ++ * that the buffer has been ++ * processed. ++ */ ++ _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ ++ _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ ++ ++ /* Flags for DMA buffer request */ ++ _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ ++ _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ ++ _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ ++}; ++ ++/** ++ * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type. ++ * ++ * \sa drmAddBufs(). ++ */ ++struct drm_buf_desc { ++ int count; /**< Number of buffers of this size */ ++ int size; /**< Size in bytes */ ++ int low_mark; /**< Low water mark */ ++ int high_mark; /**< High water mark */ ++ enum { ++ _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ ++ _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ ++ _DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */ ++ _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ ++ _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */ ++ } flags; ++ unsigned long agp_start; /**< ++ * Start address of where the AGP buffers are ++ * in the AGP aperture ++ */ ++}; ++ ++/** ++ * DRM_IOCTL_INFO_BUFS ioctl argument type. ++ */ ++struct drm_buf_info { ++ int count; /**< Entries in list */ ++ struct drm_buf_desc __user *list; ++}; ++ ++/** ++ * DRM_IOCTL_FREE_BUFS ioctl argument type. ++ */ ++struct drm_buf_free { ++ int count; ++ int __user *list; ++}; ++ ++/** ++ * Buffer information ++ * ++ * \sa drm_buf_map. ++ */ ++struct drm_buf_pub { ++ int idx; /**< Index into the master buffer list */ ++ int total; /**< Buffer size */ ++ int used; /**< Amount of buffer in use (for DMA) */ ++ void __user *address; /**< Address of buffer */ ++}; ++ ++/** ++ * DRM_IOCTL_MAP_BUFS ioctl argument type. ++ */ ++struct drm_buf_map { ++ int count; /**< Length of the buffer list */ ++ void __user *virtual; /**< Mmap'd area in user-virtual */ ++ struct drm_buf_pub __user *list; /**< Buffer information */ ++}; ++ ++/** ++ * DRM_IOCTL_DMA ioctl argument type. ++ * ++ * Indices here refer to the offset into the buffer list in drm_buf_get. ++ * ++ * \sa drmDMA(). ++ */ ++struct drm_dma { ++ int context; /**< Context handle */ ++ int send_count; /**< Number of buffers to send */ ++ int __user *send_indices; /**< List of handles to buffers */ ++ int __user *send_sizes; /**< Lengths of data to send */ ++ enum drm_dma_flags flags; /**< Flags */ ++ int request_count; /**< Number of buffers requested */ ++ int request_size; /**< Desired size for buffers */ ++ int __user *request_indices; /**< Buffer information */ ++ int __user *request_sizes; ++ int granted_count; /**< Number of buffers granted */ ++}; ++ ++enum drm_ctx_flags { ++ _DRM_CONTEXT_PRESERVED = 0x01, ++ _DRM_CONTEXT_2DONLY = 0x02 ++}; ++ ++/** ++ * DRM_IOCTL_ADD_CTX ioctl argument type. ++ * ++ * \sa drmCreateContext() and drmDestroyContext(). ++ */ ++struct drm_ctx { ++ drm_context_t handle; ++ enum drm_ctx_flags flags; ++}; ++ ++/** ++ * DRM_IOCTL_RES_CTX ioctl argument type. ++ */ ++struct drm_ctx_res { ++ int count; ++ struct drm_ctx __user *contexts; ++}; ++ ++/** ++ * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type. ++ */ ++struct drm_draw { ++ drm_drawable_t handle; ++}; ++ ++/** ++ * DRM_IOCTL_UPDATE_DRAW ioctl argument type. ++ */ ++typedef enum { ++ DRM_DRAWABLE_CLIPRECTS, ++} drm_drawable_info_type_t; ++ ++struct drm_update_draw { ++ drm_drawable_t handle; ++ unsigned int type; ++ unsigned int num; ++ unsigned long long data; ++}; ++ ++/** ++ * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. ++ */ ++struct drm_auth { ++ drm_magic_t magic; ++}; ++ ++/** ++ * DRM_IOCTL_IRQ_BUSID ioctl argument type. ++ * ++ * \sa drmGetInterruptFromBusID(). ++ */ ++struct drm_irq_busid { ++ int irq; /**< IRQ number */ ++ int busnum; /**< bus number */ ++ int devnum; /**< device number */ ++ int funcnum; /**< function number */ ++}; ++ ++enum drm_vblank_seq_type { ++ _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ ++ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ ++ /* bits 1-6 are reserved for high crtcs */ ++ _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e, ++ _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ ++ _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ ++ _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ ++ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ ++ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ ++}; ++#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1 ++ ++#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) ++#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \ ++ _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS) ++ ++struct drm_wait_vblank_request { ++ enum drm_vblank_seq_type type; ++ unsigned int sequence; ++ unsigned long signal; ++}; ++ ++struct drm_wait_vblank_reply { ++ enum drm_vblank_seq_type type; ++ unsigned int sequence; ++ long tval_sec; ++ long tval_usec; ++}; ++ ++/** ++ * DRM_IOCTL_WAIT_VBLANK ioctl argument type. ++ * ++ * \sa drmWaitVBlank(). ++ */ ++union drm_wait_vblank { ++ struct drm_wait_vblank_request request; ++ struct drm_wait_vblank_reply reply; ++}; ++ ++#define _DRM_PRE_MODESET 1 ++#define _DRM_POST_MODESET 2 ++ ++/** ++ * DRM_IOCTL_MODESET_CTL ioctl argument type ++ * ++ * \sa drmModesetCtl(). ++ */ ++struct drm_modeset_ctl { ++ __u32 crtc; ++ __u32 cmd; ++}; ++ ++/** ++ * DRM_IOCTL_AGP_ENABLE ioctl argument type. ++ * ++ * \sa drmAgpEnable(). ++ */ ++struct drm_agp_mode { ++ unsigned long mode; /**< AGP mode */ ++}; ++ ++/** ++ * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type. ++ * ++ * \sa drmAgpAlloc() and drmAgpFree(). ++ */ ++struct drm_agp_buffer { ++ unsigned long size; /**< In bytes -- will round to page boundary */ ++ unsigned long handle; /**< Used for binding / unbinding */ ++ unsigned long type; /**< Type of memory to allocate */ ++ unsigned long physical; /**< Physical used by i810 */ ++}; ++ ++/** ++ * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type. ++ * ++ * \sa drmAgpBind() and drmAgpUnbind(). ++ */ ++struct drm_agp_binding { ++ unsigned long handle; /**< From drm_agp_buffer */ ++ unsigned long offset; /**< In bytes -- will round to page boundary */ ++}; ++ ++/** ++ * DRM_IOCTL_AGP_INFO ioctl argument type. ++ * ++ * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(), ++ * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(), ++ * drmAgpVendorId() and drmAgpDeviceId(). ++ */ ++struct drm_agp_info { ++ int agp_version_major; ++ int agp_version_minor; ++ unsigned long mode; ++ unsigned long aperture_base; /* physical address */ ++ unsigned long aperture_size; /* bytes */ ++ unsigned long memory_allowed; /* bytes */ ++ unsigned long memory_used; ++ ++ /* PCI information */ ++ unsigned short id_vendor; ++ unsigned short id_device; ++}; ++ ++/** ++ * DRM_IOCTL_SG_ALLOC ioctl argument type. ++ */ ++struct drm_scatter_gather { ++ unsigned long size; /**< In bytes -- will round to page boundary */ ++ unsigned long handle; /**< Used for mapping / unmapping */ ++}; ++ ++/** ++ * DRM_IOCTL_SET_VERSION ioctl argument type. ++ */ ++struct drm_set_version { ++ int drm_di_major; ++ int drm_di_minor; ++ int drm_dd_major; ++ int drm_dd_minor; ++}; ++ ++/** DRM_IOCTL_GEM_CLOSE ioctl argument type */ ++struct drm_gem_close { ++ /** Handle of the object to be closed. */ ++ __u32 handle; ++ __u32 pad; ++}; ++ ++/** DRM_IOCTL_GEM_FLINK ioctl argument type */ ++struct drm_gem_flink { ++ /** Handle for the object being named */ ++ __u32 handle; ++ ++ /** Returned global name */ ++ __u32 name; ++}; ++ ++/** DRM_IOCTL_GEM_OPEN ioctl argument type */ ++struct drm_gem_open { ++ /** Name of object being opened */ ++ __u32 name; ++ ++ /** Returned handle for the object */ ++ __u32 handle; ++ ++ /** Returned size of the object */ ++ __u64 size; ++}; ++ ++/** DRM_IOCTL_GET_CAP ioctl argument type */ ++struct drm_get_cap { ++ __u64 capability; ++ __u64 value; ++}; ++ ++#define DRM_CLOEXEC O_CLOEXEC ++struct drm_prime_handle { ++ __u32 handle; ++ ++ /** Flags.. only applicable for handle->fd */ ++ __u32 flags; ++ ++ /** Returned dmabuf file descriptor */ ++ __s32 fd; ++}; ++ ++#include "drm_mode.h" ++ ++#define DRM_IOCTL_BASE 'd' ++#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) ++#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) ++#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type) ++#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type) ++ ++#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version) ++#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, struct drm_unique) ++#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, struct drm_auth) ++#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, struct drm_irq_busid) ++#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, struct drm_map) ++#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) ++#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) ++#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) ++#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) ++#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) ++#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) ++#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) ++#define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) ++ ++#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) ++#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) ++#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, struct drm_block) ++#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, struct drm_block) ++#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, struct drm_control) ++#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, struct drm_map) ++#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, struct drm_buf_desc) ++#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, struct drm_buf_desc) ++#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, struct drm_buf_info) ++#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, struct drm_buf_map) ++#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, struct drm_buf_free) ++ ++#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, struct drm_map) ++ ++#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) ++#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) ++ ++#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) ++#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) ++ ++#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) ++#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) ++#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) ++#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, struct drm_ctx) ++#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, struct drm_ctx) ++#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, struct drm_ctx) ++#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, struct drm_ctx_res) ++#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, struct drm_draw) ++#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, struct drm_draw) ++#define DRM_IOCTL_DMA DRM_IOWR(0x29, struct drm_dma) ++#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, struct drm_lock) ++#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock) ++#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock) ++ ++#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) ++#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) ++ ++#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) ++#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) ++#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, struct drm_agp_mode) ++#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, struct drm_agp_info) ++#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, struct drm_agp_buffer) ++#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, struct drm_agp_buffer) ++#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, struct drm_agp_binding) ++#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, struct drm_agp_binding) ++ ++#define DRM_IOCTL_SG_ALLOC DRM_IOWR(0x38, struct drm_scatter_gather) ++#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather) ++ ++#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) ++ ++#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) ++ ++#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) ++#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) ++#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc) ++#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xA3, struct drm_mode_cursor) ++#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xA4, struct drm_mode_crtc_lut) ++#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) ++#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) ++#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) ++#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) ++#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) ++ ++#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) ++#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) ++#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) ++#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) ++#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) ++#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) ++#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) ++#define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) ++ ++#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb) ++#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb) ++#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) ++#define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) ++#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) ++#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) ++#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) ++ ++/** ++ * Device specific ioctls should only be in their respective headers ++ * The device specific ioctl range is from 0x40 to 0x99. ++ * Generic IOCTLS restart at 0xA0. ++ * ++ * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and ++ * drmCommandReadWrite(). ++ */ ++#define DRM_COMMAND_BASE 0x40 ++#define DRM_COMMAND_END 0xA0 ++ ++/** ++ * Header for events written back to userspace on the drm fd. The ++ * type defines the type of event, the length specifies the total ++ * length of the event (including the header), and user_data is ++ * typically a 64 bit value passed with the ioctl that triggered the ++ * event. A read on the drm fd will always only return complete ++ * events, that is, if for example the read buffer is 100 bytes, and ++ * there are two 64 byte events pending, only one will be returned. ++ * ++ * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and ++ * up are chipset specific. ++ */ ++struct drm_event { ++ __u32 type; ++ __u32 length; ++}; ++ ++#define DRM_EVENT_VBLANK 0x01 ++#define DRM_EVENT_FLIP_COMPLETE 0x02 ++ ++struct drm_event_vblank { ++ struct drm_event base; ++ __u64 user_data; ++ __u32 tv_sec; ++ __u32 tv_usec; ++ __u32 sequence; ++ __u32 reserved; ++}; ++ ++#define DRM_CAP_DUMB_BUFFER 0x1 ++#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 ++#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 ++#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 ++ ++/* typedef area */ ++#ifndef __KERNEL__ ++typedef struct drm_clip_rect drm_clip_rect_t; ++typedef struct drm_drawable_info drm_drawable_info_t; ++typedef struct drm_tex_region drm_tex_region_t; ++typedef struct drm_hw_lock drm_hw_lock_t; ++typedef struct drm_version drm_version_t; ++typedef struct drm_unique drm_unique_t; ++typedef struct drm_list drm_list_t; ++typedef struct drm_block drm_block_t; ++typedef struct drm_control drm_control_t; ++typedef enum drm_map_type drm_map_type_t; ++typedef enum drm_map_flags drm_map_flags_t; ++typedef struct drm_ctx_priv_map drm_ctx_priv_map_t; ++typedef struct drm_map drm_map_t; ++typedef struct drm_client drm_client_t; ++typedef enum drm_stat_type drm_stat_type_t; ++typedef struct drm_stats drm_stats_t; ++typedef enum drm_lock_flags drm_lock_flags_t; ++typedef struct drm_lock drm_lock_t; ++typedef enum drm_dma_flags drm_dma_flags_t; ++typedef struct drm_buf_desc drm_buf_desc_t; ++typedef struct drm_buf_info drm_buf_info_t; ++typedef struct drm_buf_free drm_buf_free_t; ++typedef struct drm_buf_pub drm_buf_pub_t; ++typedef struct drm_buf_map drm_buf_map_t; ++typedef struct drm_dma drm_dma_t; ++typedef union drm_wait_vblank drm_wait_vblank_t; ++typedef struct drm_agp_mode drm_agp_mode_t; ++typedef enum drm_ctx_flags drm_ctx_flags_t; ++typedef struct drm_ctx drm_ctx_t; ++typedef struct drm_ctx_res drm_ctx_res_t; ++typedef struct drm_draw drm_draw_t; ++typedef struct drm_update_draw drm_update_draw_t; ++typedef struct drm_auth drm_auth_t; ++typedef struct drm_irq_busid drm_irq_busid_t; ++typedef enum drm_vblank_seq_type drm_vblank_seq_type_t; ++ ++typedef struct drm_agp_buffer drm_agp_buffer_t; ++typedef struct drm_agp_binding drm_agp_binding_t; ++typedef struct drm_agp_info drm_agp_info_t; ++typedef struct drm_scatter_gather drm_scatter_gather_t; ++typedef struct drm_set_version drm_set_version_t; ++#endif ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drmP.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drmP.h +new file mode 100644 +index 0000000..dd73104 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drmP.h +@@ -0,0 +1,1778 @@ ++/** ++ * \file drmP.h ++ * Private header for Direct Rendering Manager ++ * ++ * \author Rickard E. (Rik) Faith ++ * \author Gareth Hughes ++ */ ++ ++/* ++ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * Copyright (c) 2009-2010, Code Aurora Forum. ++ * All rights reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _DRM_P_H_ ++#define _DRM_P_H_ ++ ++#ifdef __KERNEL__ ++#ifdef __alpha__ ++/* add include of current.h so that "current" is defined ++ * before static inline funcs in wait.h. Doing this so we ++ * can build the DRM (part of PI DRI). 4/21/2000 S + B */ ++#include ++#endif /* __alpha__ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(__alpha__) || defined(__powerpc__) ++#include /* For pte_wrprotect */ ++#endif ++#include ++#include ++#include ++#ifdef CONFIG_MTRR ++#include ++#endif ++#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) ++#include ++#include ++#endif ++#include ++#include ++#include ++#include "drm.h" ++ ++#include ++ ++#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) ++#define __OS_HAS_MTRR (defined(CONFIG_MTRR)) ++ ++struct module; ++ ++struct drm_file; ++struct drm_device; ++ ++#include "drm_os_linux.h" ++#include "drm_hashtab.h" ++#include "drm_mm.h" ++ ++#define DRM_UT_CORE 0x01 ++#define DRM_UT_DRIVER 0x02 ++#define DRM_UT_KMS 0x04 ++#define DRM_UT_PRIME 0x08 ++/* ++ * Three debug levels are defined. ++ * drm_core, drm_driver, drm_kms ++ * drm_core level can be used in the generic drm code. For example: ++ * drm_ioctl, drm_mm, drm_memory ++ * The macro definition of DRM_DEBUG is used. ++ * DRM_DEBUG(fmt, args...) ++ * The debug info by using the DRM_DEBUG can be obtained by adding ++ * the boot option of "drm.debug=1". ++ * ++ * drm_driver level can be used in the specific drm driver. It is used ++ * to add the debug info related with the drm driver. For example: ++ * i915_drv, i915_dma, i915_gem, radeon_drv, ++ * The macro definition of DRM_DEBUG_DRIVER can be used. ++ * DRM_DEBUG_DRIVER(fmt, args...) ++ * The debug info by using the DRM_DEBUG_DRIVER can be obtained by ++ * adding the boot option of "drm.debug=0x02" ++ * ++ * drm_kms level can be used in the KMS code related with specific drm driver. ++ * It is used to add the debug info related with KMS mode. For example: ++ * the connector/crtc , ++ * The macro definition of DRM_DEBUG_KMS can be used. ++ * DRM_DEBUG_KMS(fmt, args...) ++ * The debug info by using the DRM_DEBUG_KMS can be obtained by ++ * adding the boot option of "drm.debug=0x04" ++ * ++ * If we add the boot option of "drm.debug=0x06", we can get the debug info by ++ * using the DRM_DEBUG_KMS and DRM_DEBUG_DRIVER. ++ * If we add the boot option of "drm.debug=0x05", we can get the debug info by ++ * using the DRM_DEBUG_KMS and DRM_DEBUG. ++ */ ++ ++extern __printf(4, 5) ++void drm_ut_debug_printk(unsigned int request_level, ++ const char *prefix, ++ const char *function_name, ++ const char *format, ...); ++extern __printf(2, 3) ++int drm_err(const char *func, const char *format, ...); ++ ++/***********************************************************************/ ++/** \name DRM template customization defaults */ ++/*@{*/ ++ ++/* driver capabilities and requirements mask */ ++#define DRIVER_USE_AGP 0x1 ++#define DRIVER_REQUIRE_AGP 0x2 ++#define DRIVER_USE_MTRR 0x4 ++#define DRIVER_PCI_DMA 0x8 ++#define DRIVER_SG 0x10 ++#define DRIVER_HAVE_DMA 0x20 ++#define DRIVER_HAVE_IRQ 0x40 ++#define DRIVER_IRQ_SHARED 0x80 ++#define DRIVER_IRQ_VBL 0x100 ++#define DRIVER_DMA_QUEUE 0x200 ++#define DRIVER_FB_DMA 0x400 ++#define DRIVER_IRQ_VBL2 0x800 ++#define DRIVER_GEM 0x1000 ++#define DRIVER_MODESET 0x2000 ++#define DRIVER_PRIME 0x4000 ++ ++#define DRIVER_BUS_PCI 0x1 ++#define DRIVER_BUS_PLATFORM 0x2 ++#define DRIVER_BUS_USB 0x3 ++ ++/***********************************************************************/ ++/** \name Begin the DRM... */ ++/*@{*/ ++ ++#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then ++ also include looping detection. */ ++ ++#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */ ++#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ ++#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ ++#define DRM_LOOPING_LIMIT 5000000 ++#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ ++#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ ++ ++#define DRM_FLAG_DEBUG 0x01 ++ ++#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) ++#define DRM_MAP_HASH_OFFSET 0x10000000 ++ ++/*@}*/ ++ ++/***********************************************************************/ ++/** \name Macros to make printk easier */ ++/*@{*/ ++ ++/** ++ * Error output. ++ * ++ * \param fmt printf() like format string. ++ * \param arg arguments ++ */ ++#define DRM_ERROR(fmt, ...) \ ++ drm_err(__func__, fmt, ##__VA_ARGS__) ++ ++#define DRM_INFO(fmt, ...) \ ++ printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__) ++ ++/** ++ * Debug output. ++ * ++ * \param fmt printf() like format string. ++ * \param arg arguments ++ */ ++#if DRM_DEBUG_CODE ++#define DRM_DEBUG(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME, \ ++ __func__, fmt, ##args); \ ++ } while (0) ++ ++#define DRM_DEBUG_DRIVER(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_DRIVER, DRM_NAME, \ ++ __func__, fmt, ##args); \ ++ } while (0) ++#define DRM_DEBUG_KMS(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \ ++ __func__, fmt, ##args); \ ++ } while (0) ++#define DRM_DEBUG_PRIME(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \ ++ __func__, fmt, ##args); \ ++ } while (0) ++#define DRM_LOG(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_CORE, NULL, \ ++ NULL, fmt, ##args); \ ++ } while (0) ++#define DRM_LOG_KMS(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_KMS, NULL, \ ++ NULL, fmt, ##args); \ ++ } while (0) ++#define DRM_LOG_MODE(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_MODE, NULL, \ ++ NULL, fmt, ##args); \ ++ } while (0) ++#define DRM_LOG_DRIVER(fmt, args...) \ ++ do { \ ++ drm_ut_debug_printk(DRM_UT_DRIVER, NULL, \ ++ NULL, fmt, ##args); \ ++ } while (0) ++#else ++#define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0) ++#define DRM_DEBUG_KMS(fmt, args...) do { } while (0) ++#define DRM_DEBUG_PRIME(fmt, args...) do { } while (0) ++#define DRM_DEBUG(fmt, arg...) do { } while (0) ++#define DRM_LOG(fmt, arg...) do { } while (0) ++#define DRM_LOG_KMS(fmt, args...) do { } while (0) ++#define DRM_LOG_MODE(fmt, arg...) do { } while (0) ++#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0) ++ ++#endif ++ ++/*@}*/ ++ ++/***********************************************************************/ ++/** \name Internal types and structures */ ++/*@{*/ ++ ++#define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x) ++ ++#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1)) ++#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) ++ ++#define DRM_IF_VERSION(maj, min) (maj << 16 | min) ++ ++/** ++ * Test that the hardware lock is held by the caller, returning otherwise. ++ * ++ * \param dev DRM device. ++ * \param filp file pointer of the caller. ++ */ ++#define LOCK_TEST_WITH_RETURN( dev, _file_priv ) \ ++do { \ ++ if (!_DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock) || \ ++ _file_priv->master->lock.file_priv != _file_priv) { \ ++ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ ++ __func__, _DRM_LOCK_IS_HELD(_file_priv->master->lock.hw_lock->lock),\ ++ _file_priv->master->lock.file_priv, _file_priv); \ ++ return -EINVAL; \ ++ } \ ++} while (0) ++ ++/** ++ * Ioctl function type. ++ * ++ * \param inode device inode. ++ * \param file_priv DRM file private pointer. ++ * \param cmd command. ++ * \param arg argument. ++ */ ++typedef int drm_ioctl_t(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd, ++ unsigned long arg); ++ ++#define DRM_IOCTL_NR(n) _IOC_NR(n) ++#define DRM_MAJOR 226 ++ ++#define DRM_AUTH 0x1 ++#define DRM_MASTER 0x2 ++#define DRM_ROOT_ONLY 0x4 ++#define DRM_CONTROL_ALLOW 0x8 ++#define DRM_UNLOCKED 0x10 ++ ++struct drm_ioctl_desc { ++ unsigned int cmd; ++ int flags; ++ drm_ioctl_t *func; ++ unsigned int cmd_drv; ++}; ++ ++/** ++ * Creates a driver or general drm_ioctl_desc array entry for the given ++ * ioctl, for use by drm_ioctl(). ++ */ ++ ++#define DRM_IOCTL_DEF_DRV(ioctl, _func, _flags) \ ++ [DRM_IOCTL_NR(DRM_##ioctl)] = {.cmd = DRM_##ioctl, .func = _func, .flags = _flags, .cmd_drv = DRM_IOCTL_##ioctl} ++ ++struct drm_magic_entry { ++ struct list_head head; ++ struct drm_hash_item hash_item; ++ struct drm_file *priv; ++}; ++ ++struct drm_vma_entry { ++ struct list_head head; ++ struct vm_area_struct *vma; ++ pid_t pid; ++}; ++ ++/** ++ * DMA buffer. ++ */ ++struct drm_buf { ++ int idx; /**< Index into master buflist */ ++ int total; /**< Buffer size */ ++ int order; /**< log-base-2(total) */ ++ int used; /**< Amount of buffer in use (for DMA) */ ++ unsigned long offset; /**< Byte offset (used internally) */ ++ void *address; /**< Address of buffer */ ++ unsigned long bus_address; /**< Bus address of buffer */ ++ struct drm_buf *next; /**< Kernel-only: used for free list */ ++ __volatile__ int waiting; /**< On kernel DMA queue */ ++ __volatile__ int pending; /**< On hardware DMA queue */ ++ wait_queue_head_t dma_wait; /**< Processes waiting */ ++ struct drm_file *file_priv; /**< Private of holding file descr */ ++ int context; /**< Kernel queue for this buffer */ ++ int while_locked; /**< Dispatch this buffer while locked */ ++ enum { ++ DRM_LIST_NONE = 0, ++ DRM_LIST_FREE = 1, ++ DRM_LIST_WAIT = 2, ++ DRM_LIST_PEND = 3, ++ DRM_LIST_PRIO = 4, ++ DRM_LIST_RECLAIM = 5 ++ } list; /**< Which list we're on */ ++ ++ int dev_priv_size; /**< Size of buffer private storage */ ++ void *dev_private; /**< Per-buffer private storage */ ++}; ++ ++/** bufs is one longer than it has to be */ ++struct drm_waitlist { ++ int count; /**< Number of possible buffers */ ++ struct drm_buf **bufs; /**< List of pointers to buffers */ ++ struct drm_buf **rp; /**< Read pointer */ ++ struct drm_buf **wp; /**< Write pointer */ ++ struct drm_buf **end; /**< End pointer */ ++ spinlock_t read_lock; ++ spinlock_t write_lock; ++}; ++ ++struct drm_freelist { ++ int initialized; /**< Freelist in use */ ++ atomic_t count; /**< Number of free buffers */ ++ struct drm_buf *next; /**< End pointer */ ++ ++ wait_queue_head_t waiting; /**< Processes waiting on free bufs */ ++ int low_mark; /**< Low water mark */ ++ int high_mark; /**< High water mark */ ++ atomic_t wfh; /**< If waiting for high mark */ ++ spinlock_t lock; ++}; ++ ++typedef struct drm_dma_handle { ++ dma_addr_t busaddr; ++ void *vaddr; ++ size_t size; ++} drm_dma_handle_t; ++ ++/** ++ * Buffer entry. There is one of this for each buffer size order. ++ */ ++struct drm_buf_entry { ++ int buf_size; /**< size */ ++ int buf_count; /**< number of buffers */ ++ struct drm_buf *buflist; /**< buffer list */ ++ int seg_count; ++ int page_order; ++ struct drm_dma_handle **seglist; ++ ++ struct drm_freelist freelist; ++}; ++ ++/* Event queued up for userspace to read */ ++struct drm_pending_event { ++ struct drm_event *event; ++ struct list_head link; ++ struct drm_file *file_priv; ++ pid_t pid; /* pid of requester, no guarantee it's valid by the time ++ we deliver the event, for tracing only */ ++ void (*destroy)(struct drm_pending_event *event); ++}; ++ ++/* initial implementaton using a linked list - todo hashtab */ ++struct drm_prime_file_private { ++ struct list_head head; ++ struct mutex lock; ++}; ++ ++/** File private data */ ++struct drm_file { ++ int authenticated; ++ pid_t pid; ++ uid_t uid; ++ drm_magic_t magic; ++ unsigned long ioctl_count; ++ struct list_head lhead; ++ struct drm_minor *minor; ++ unsigned long lock_count; ++ ++ /** Mapping of mm object handles to object pointers. */ ++ struct idr object_idr; ++ /** Lock for synchronization of access to object_idr. */ ++ spinlock_t table_lock; ++ ++ struct file *filp; ++ void *driver_priv; ++ ++ int is_master; /* this file private is a master for a minor */ ++ struct drm_master *master; /* master this node is currently associated with ++ N.B. not always minor->master */ ++ struct list_head fbs; ++ ++ wait_queue_head_t event_wait; ++ struct list_head event_list; ++ int event_space; ++ ++ struct drm_prime_file_private prime; ++}; ++ ++/** Wait queue */ ++struct drm_queue { ++ atomic_t use_count; /**< Outstanding uses (+1) */ ++ atomic_t finalization; /**< Finalization in progress */ ++ atomic_t block_count; /**< Count of processes waiting */ ++ atomic_t block_read; /**< Queue blocked for reads */ ++ wait_queue_head_t read_queue; /**< Processes waiting on block_read */ ++ atomic_t block_write; /**< Queue blocked for writes */ ++ wait_queue_head_t write_queue; /**< Processes waiting on block_write */ ++ atomic_t total_queued; /**< Total queued statistic */ ++ atomic_t total_flushed; /**< Total flushes statistic */ ++ atomic_t total_locks; /**< Total locks statistics */ ++ enum drm_ctx_flags flags; /**< Context preserving and 2D-only */ ++ struct drm_waitlist waitlist; /**< Pending buffers */ ++ wait_queue_head_t flush_queue; /**< Processes waiting until flush */ ++}; ++ ++/** ++ * Lock data. ++ */ ++struct drm_lock_data { ++ struct drm_hw_lock *hw_lock; /**< Hardware lock */ ++ /** Private of lock holder's file (NULL=kernel) */ ++ struct drm_file *file_priv; ++ wait_queue_head_t lock_queue; /**< Queue of blocked processes */ ++ unsigned long lock_time; /**< Time of last lock in jiffies */ ++ spinlock_t spinlock; ++ uint32_t kernel_waiters; ++ uint32_t user_waiters; ++ int idle_has_lock; ++}; ++ ++/** ++ * DMA data. ++ */ ++struct drm_device_dma { ++ ++ struct drm_buf_entry bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */ ++ int buf_count; /**< total number of buffers */ ++ struct drm_buf **buflist; /**< Vector of pointers into drm_device_dma::bufs */ ++ int seg_count; ++ int page_count; /**< number of pages */ ++ unsigned long *pagelist; /**< page list */ ++ unsigned long byte_count; ++ enum { ++ _DRM_DMA_USE_AGP = 0x01, ++ _DRM_DMA_USE_SG = 0x02, ++ _DRM_DMA_USE_FB = 0x04, ++ _DRM_DMA_USE_PCI_RO = 0x08 ++ } flags; ++ ++}; ++ ++/** ++ * AGP memory entry. Stored as a doubly linked list. ++ */ ++struct drm_agp_mem { ++ unsigned long handle; /**< handle */ ++ DRM_AGP_MEM *memory; ++ unsigned long bound; /**< address */ ++ int pages; ++ struct list_head head; ++}; ++ ++/** ++ * AGP data. ++ * ++ * \sa drm_agp_init() and drm_device::agp. ++ */ ++struct drm_agp_head { ++ DRM_AGP_KERN agp_info; /**< AGP device information */ ++ struct list_head memory; ++ unsigned long mode; /**< AGP mode */ ++ struct agp_bridge_data *bridge; ++ int enabled; /**< whether the AGP bus as been enabled */ ++ int acquired; /**< whether the AGP device has been acquired */ ++ unsigned long base; ++ int agp_mtrr; ++ int cant_use_aperture; ++ unsigned long page_mask; ++}; ++ ++/** ++ * Scatter-gather memory. ++ */ ++struct drm_sg_mem { ++ unsigned long handle; ++ void *virtual; ++ int pages; ++ struct page **pagelist; ++ dma_addr_t *busaddr; ++}; ++ ++struct drm_sigdata { ++ int context; ++ struct drm_hw_lock *lock; ++}; ++ ++ ++/** ++ * Kernel side of a mapping ++ */ ++struct drm_local_map { ++ resource_size_t offset; /**< Requested physical address (0 for SAREA)*/ ++ unsigned long size; /**< Requested physical size (bytes) */ ++ enum drm_map_type type; /**< Type of memory to map */ ++ enum drm_map_flags flags; /**< Flags */ ++ void *handle; /**< User-space: "Handle" to pass to mmap() */ ++ /**< Kernel-space: kernel-virtual address */ ++ int mtrr; /**< MTRR slot used */ ++}; ++ ++typedef struct drm_local_map drm_local_map_t; ++ ++/** ++ * Mappings list ++ */ ++struct drm_map_list { ++ struct list_head head; /**< list head */ ++ struct drm_hash_item hash; ++ struct drm_local_map *map; /**< mapping */ ++ uint64_t user_token; ++ struct drm_master *master; ++ struct drm_mm_node *file_offset_node; /**< fake offset */ ++}; ++ ++/** ++ * Context handle list ++ */ ++struct drm_ctx_list { ++ struct list_head head; /**< list head */ ++ drm_context_t handle; /**< context handle */ ++ struct drm_file *tag; /**< associated fd private data */ ++}; ++ ++/* location of GART table */ ++#define DRM_ATI_GART_MAIN 1 ++#define DRM_ATI_GART_FB 2 ++ ++#define DRM_ATI_GART_PCI 1 ++#define DRM_ATI_GART_PCIE 2 ++#define DRM_ATI_GART_IGP 3 ++ ++struct drm_ati_pcigart_info { ++ int gart_table_location; ++ int gart_reg_if; ++ void *addr; ++ dma_addr_t bus_addr; ++ dma_addr_t table_mask; ++ struct drm_dma_handle *table_handle; ++ struct drm_local_map mapping; ++ int table_size; ++}; ++ ++/** ++ * GEM specific mm private for tracking GEM objects ++ */ ++struct drm_gem_mm { ++ struct drm_mm offset_manager; /**< Offset mgmt for buffer objects */ ++ struct drm_open_hash offset_hash; /**< User token hash table for maps */ ++}; ++ ++/** ++ * This structure defines the drm_mm memory object, which will be used by the ++ * DRM for its buffer objects. ++ */ ++struct drm_gem_object { ++ /** Reference count of this object */ ++ struct kref refcount; ++ ++ /** Handle count of this object. Each handle also holds a reference */ ++ atomic_t handle_count; /* number of handles on this object */ ++ ++ /** Related drm device */ ++ struct drm_device *dev; ++ ++ /** File representing the shmem storage */ ++ struct file *filp; ++ ++ /* Mapping info for this object */ ++ struct drm_map_list map_list; ++ ++ /** ++ * Size of the object, in bytes. Immutable over the object's ++ * lifetime. ++ */ ++ size_t size; ++ ++ /** ++ * Global name for this object, starts at 1. 0 means unnamed. ++ * Access is covered by the object_name_lock in the related drm_device ++ */ ++ int name; ++ ++ /** ++ * Memory domains. These monitor which caches contain read/write data ++ * related to the object. When transitioning from one set of domains ++ * to another, the driver is called to ensure that caches are suitably ++ * flushed and invalidated ++ */ ++ uint32_t read_domains; ++ uint32_t write_domain; ++ ++ /** ++ * While validating an exec operation, the ++ * new read/write domain values are computed here. ++ * They will be transferred to the above values ++ * at the point that any cache flushing occurs ++ */ ++ uint32_t pending_read_domains; ++ uint32_t pending_write_domain; ++ ++ void *driver_private; ++ ++ /* dma buf exported from this GEM object */ ++ struct dma_buf *export_dma_buf; ++ ++ /* dma buf attachment backing this object */ ++ struct dma_buf_attachment *import_attach; ++}; ++ ++#include "drm_crtc.h" ++ ++/* per-master structure */ ++struct drm_master { ++ ++ struct kref refcount; /* refcount for this master */ ++ ++ struct list_head head; /**< each minor contains a list of masters */ ++ struct drm_minor *minor; /**< link back to minor we are a master for */ ++ ++ char *unique; /**< Unique identifier: e.g., busid */ ++ int unique_len; /**< Length of unique field */ ++ int unique_size; /**< amount allocated */ ++ ++ int blocked; /**< Blocked due to VC switch? */ ++ ++ /** \name Authentication */ ++ /*@{ */ ++ struct drm_open_hash magiclist; ++ struct list_head magicfree; ++ /*@} */ ++ ++ struct drm_lock_data lock; /**< Information on hardware lock */ ++ ++ void *driver_priv; /**< Private structure for driver to use */ ++}; ++ ++/* Size of ringbuffer for vblank timestamps. Just double-buffer ++ * in initial implementation. ++ */ ++#define DRM_VBLANKTIME_RBSIZE 2 ++ ++/* Flags and return codes for get_vblank_timestamp() driver function. */ ++#define DRM_CALLED_FROM_VBLIRQ 1 ++#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) ++#define DRM_VBLANKTIME_INVBL (1 << 1) ++ ++/* get_scanout_position() return flags */ ++#define DRM_SCANOUTPOS_VALID (1 << 0) ++#define DRM_SCANOUTPOS_INVBL (1 << 1) ++#define DRM_SCANOUTPOS_ACCURATE (1 << 2) ++ ++struct drm_bus { ++ int bus_type; ++ int (*get_irq)(struct drm_device *dev); ++ const char *(*get_name)(struct drm_device *dev); ++ int (*set_busid)(struct drm_device *dev, struct drm_master *master); ++ int (*set_unique)(struct drm_device *dev, struct drm_master *master, ++ struct drm_unique *unique); ++ int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p); ++ /* hooks that are for PCI */ ++ int (*agp_init)(struct drm_device *dev); ++ ++}; ++ ++/** ++ * DRM driver structure. This structure represent the common code for ++ * a family of cards. There will one drm_device for each card present ++ * in this family ++ */ ++struct drm_driver { ++ int (*load) (struct drm_device *, unsigned long flags); ++ int (*firstopen) (struct drm_device *); ++ int (*open) (struct drm_device *, struct drm_file *); ++ void (*preclose) (struct drm_device *, struct drm_file *file_priv); ++ void (*postclose) (struct drm_device *, struct drm_file *); ++ void (*lastclose) (struct drm_device *); ++ int (*unload) (struct drm_device *); ++ int (*suspend) (struct drm_device *, pm_message_t state); ++ int (*resume) (struct drm_device *); ++ int (*dma_ioctl) (struct drm_device *dev, void *data, struct drm_file *file_priv); ++ int (*dma_quiescent) (struct drm_device *); ++ int (*context_dtor) (struct drm_device *dev, int context); ++ ++ /** ++ * get_vblank_counter - get raw hardware vblank counter ++ * @dev: DRM device ++ * @crtc: counter to fetch ++ * ++ * Driver callback for fetching a raw hardware vblank counter ++ * for @crtc. If a device doesn't have a hardware counter, the ++ * driver can simply return the value of drm_vblank_count and ++ * make the enable_vblank() and disable_vblank() hooks into no-ops, ++ * leaving interrupts enabled at all times. ++ * ++ * Wraparound handling and loss of events due to modesetting is dealt ++ * with in the DRM core code. ++ * ++ * RETURNS ++ * Raw vblank counter value. ++ */ ++ u32 (*get_vblank_counter) (struct drm_device *dev, int crtc); ++ ++ /** ++ * enable_vblank - enable vblank interrupt events ++ * @dev: DRM device ++ * @crtc: which irq to enable ++ * ++ * Enable vblank interrupts for @crtc. If the device doesn't have ++ * a hardware vblank counter, this routine should be a no-op, since ++ * interrupts will have to stay on to keep the count accurate. ++ * ++ * RETURNS ++ * Zero on success, appropriate errno if the given @crtc's vblank ++ * interrupt cannot be enabled. ++ */ ++ int (*enable_vblank) (struct drm_device *dev, int crtc); ++ ++ /** ++ * disable_vblank - disable vblank interrupt events ++ * @dev: DRM device ++ * @crtc: which irq to enable ++ * ++ * Disable vblank interrupts for @crtc. If the device doesn't have ++ * a hardware vblank counter, this routine should be a no-op, since ++ * interrupts will have to stay on to keep the count accurate. ++ */ ++ void (*disable_vblank) (struct drm_device *dev, int crtc); ++ ++ /** ++ * Called by \c drm_device_is_agp. Typically used to determine if a ++ * card is really attached to AGP or not. ++ * ++ * \param dev DRM device handle ++ * ++ * \returns ++ * One of three values is returned depending on whether or not the ++ * card is absolutely \b not AGP (return of 0), absolutely \b is AGP ++ * (return of 1), or may or may not be AGP (return of 2). ++ */ ++ int (*device_is_agp) (struct drm_device *dev); ++ ++ /** ++ * Called by vblank timestamping code. ++ * ++ * Return the current display scanout position from a crtc. ++ * ++ * \param dev DRM device. ++ * \param crtc Id of the crtc to query. ++ * \param *vpos Target location for current vertical scanout position. ++ * \param *hpos Target location for current horizontal scanout position. ++ * ++ * Returns vpos as a positive number while in active scanout area. ++ * Returns vpos as a negative number inside vblank, counting the number ++ * of scanlines to go until end of vblank, e.g., -1 means "one scanline ++ * until start of active scanout / end of vblank." ++ * ++ * \return Flags, or'ed together as follows: ++ * ++ * DRM_SCANOUTPOS_VALID = Query successful. ++ * DRM_SCANOUTPOS_INVBL = Inside vblank. ++ * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of ++ * this flag means that returned position may be offset by a constant ++ * but unknown small number of scanlines wrt. real scanout position. ++ * ++ */ ++ int (*get_scanout_position) (struct drm_device *dev, int crtc, ++ int *vpos, int *hpos); ++ ++ /** ++ * Called by \c drm_get_last_vbltimestamp. Should return a precise ++ * timestamp when the most recent VBLANK interval ended or will end. ++ * ++ * Specifically, the timestamp in @vblank_time should correspond as ++ * closely as possible to the time when the first video scanline of ++ * the video frame after the end of VBLANK will start scanning out, ++ * the time immediately after end of the VBLANK interval. If the ++ * @crtc is currently inside VBLANK, this will be a time in the future. ++ * If the @crtc is currently scanning out a frame, this will be the ++ * past start time of the current scanout. This is meant to adhere ++ * to the OpenML OML_sync_control extension specification. ++ * ++ * \param dev dev DRM device handle. ++ * \param crtc crtc for which timestamp should be returned. ++ * \param *max_error Maximum allowable timestamp error in nanoseconds. ++ * Implementation should strive to provide timestamp ++ * with an error of at most *max_error nanoseconds. ++ * Returns true upper bound on error for timestamp. ++ * \param *vblank_time Target location for returned vblank timestamp. ++ * \param flags 0 = Defaults, no special treatment needed. ++ * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank ++ * irq handler. Some drivers need to apply some workarounds ++ * for gpu-specific vblank irq quirks if flag is set. ++ * ++ * \returns ++ * Zero if timestamping isn't supported in current display mode or a ++ * negative number on failure. A positive status code on success, ++ * which describes how the vblank_time timestamp was computed. ++ */ ++ int (*get_vblank_timestamp) (struct drm_device *dev, int crtc, ++ int *max_error, ++ struct timeval *vblank_time, ++ unsigned flags); ++ ++ /* these have to be filled in */ ++ ++ irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); ++ void (*irq_preinstall) (struct drm_device *dev); ++ int (*irq_postinstall) (struct drm_device *dev); ++ void (*irq_uninstall) (struct drm_device *dev); ++ void (*reclaim_buffers) (struct drm_device *dev, ++ struct drm_file * file_priv); ++ void (*reclaim_buffers_locked) (struct drm_device *dev, ++ struct drm_file *file_priv); ++ void (*reclaim_buffers_idlelocked) (struct drm_device *dev, ++ struct drm_file *file_priv); ++ void (*set_version) (struct drm_device *dev, ++ struct drm_set_version *sv); ++ ++ /* Master routines */ ++ int (*master_create)(struct drm_device *dev, struct drm_master *master); ++ void (*master_destroy)(struct drm_device *dev, struct drm_master *master); ++ /** ++ * master_set is called whenever the minor master is set. ++ * master_drop is called whenever the minor master is dropped. ++ */ ++ ++ int (*master_set)(struct drm_device *dev, struct drm_file *file_priv, ++ bool from_open); ++ void (*master_drop)(struct drm_device *dev, struct drm_file *file_priv, ++ bool from_release); ++ ++ int (*debugfs_init)(struct drm_minor *minor); ++ void (*debugfs_cleanup)(struct drm_minor *minor); ++ ++ /** ++ * Driver-specific constructor for drm_gem_objects, to set up ++ * obj->driver_private. ++ * ++ * Returns 0 on success. ++ */ ++ int (*gem_init_object) (struct drm_gem_object *obj); ++ void (*gem_free_object) (struct drm_gem_object *obj); ++ int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); ++ void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); ++ ++ /* prime: */ ++ /* export handle -> fd (see drm_gem_prime_handle_to_fd() helper) */ ++ int (*prime_handle_to_fd)(struct drm_device *dev, struct drm_file *file_priv, ++ uint32_t handle, uint32_t flags, int *prime_fd); ++ /* import fd -> handle (see drm_gem_prime_fd_to_handle() helper) */ ++ int (*prime_fd_to_handle)(struct drm_device *dev, struct drm_file *file_priv, ++ int prime_fd, uint32_t *handle); ++ /* export GEM -> dmabuf */ ++ struct dma_buf * (*gem_prime_export)(struct drm_device *dev, ++ struct drm_gem_object *obj, int flags); ++ /* import dmabuf -> GEM */ ++ struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev, ++ struct dma_buf *dma_buf); ++ ++ /* vga arb irq handler */ ++ void (*vgaarb_irq)(struct drm_device *dev, bool state); ++ ++ /* dumb alloc support */ ++ int (*dumb_create)(struct drm_file *file_priv, ++ struct drm_device *dev, ++ struct drm_mode_create_dumb *args); ++ int (*dumb_map_offset)(struct drm_file *file_priv, ++ struct drm_device *dev, uint32_t handle, ++ uint64_t *offset); ++ int (*dumb_destroy)(struct drm_file *file_priv, ++ struct drm_device *dev, ++ uint32_t handle); ++ ++ /* Driver private ops for this object */ ++ struct vm_operations_struct *gem_vm_ops; ++ ++ int major; ++ int minor; ++ int patchlevel; ++ char *name; ++ char *desc; ++ char *date; ++ ++ u32 driver_features; ++ int dev_priv_size; ++ struct drm_ioctl_desc *ioctls; ++ int num_ioctls; ++ const struct file_operations *fops; ++ union { ++ struct pci_driver *pci; ++ struct platform_device *platform_device; ++ struct usb_driver *usb; ++ } kdriver; ++ struct drm_bus *bus; ++ ++ /* List of devices hanging off this driver */ ++ struct list_head device_list; ++}; ++ ++#define DRM_MINOR_UNASSIGNED 0 ++#define DRM_MINOR_LEGACY 1 ++#define DRM_MINOR_CONTROL 2 ++#define DRM_MINOR_RENDER 3 ++ ++ ++/** ++ * debugfs node list. This structure represents a debugfs file to ++ * be created by the drm core ++ */ ++struct drm_debugfs_list { ++ const char *name; /** file name */ ++ int (*show)(struct seq_file*, void*); /** show callback */ ++ u32 driver_features; /**< Required driver features for this entry */ ++}; ++ ++/** ++ * debugfs node structure. This structure represents a debugfs file. ++ */ ++struct drm_debugfs_node { ++ struct list_head list; ++ struct drm_minor *minor; ++ struct drm_debugfs_list *debugfs_ent; ++ struct dentry *dent; ++}; ++ ++/** ++ * Info file list entry. This structure represents a debugfs or proc file to ++ * be created by the drm core ++ */ ++struct drm_info_list { ++ const char *name; /** file name */ ++ int (*show)(struct seq_file*, void*); /** show callback */ ++ u32 driver_features; /**< Required driver features for this entry */ ++ void *data; ++}; ++ ++/** ++ * debugfs node structure. This structure represents a debugfs file. ++ */ ++struct drm_info_node { ++ struct list_head list; ++ struct drm_minor *minor; ++ struct drm_info_list *info_ent; ++ struct dentry *dent; ++}; ++ ++/** ++ * DRM minor structure. This structure represents a drm minor number. ++ */ ++struct drm_minor { ++ int index; /**< Minor device number */ ++ int type; /**< Control or render */ ++ dev_t device; /**< Device number for mknod */ ++ struct device kdev; /**< Linux device */ ++ struct drm_device *dev; ++ ++ struct proc_dir_entry *proc_root; /**< proc directory entry */ ++ struct drm_info_node proc_nodes; ++ struct dentry *debugfs_root; ++ ++ struct list_head debugfs_list; ++ struct mutex debugfs_lock; /* Protects debugfs_list. */ ++ ++ struct drm_master *master; /* currently active master for this node */ ++ struct list_head master_list; ++ struct drm_mode_group mode_group; ++}; ++ ++/* mode specified on the command line */ ++struct drm_cmdline_mode { ++ bool specified; ++ bool refresh_specified; ++ bool bpp_specified; ++ int xres, yres; ++ int bpp; ++ int refresh; ++ bool rb; ++ bool interlace; ++ bool cvt; ++ bool margins; ++ enum drm_connector_force force; ++}; ++ ++ ++struct drm_pending_vblank_event { ++ struct drm_pending_event base; ++ int pipe; ++ struct drm_event_vblank event; ++}; ++ ++/** ++ * DRM device structure. This structure represent a complete card that ++ * may contain multiple heads. ++ */ ++struct drm_device { ++ struct list_head driver_item; /**< list of devices per driver */ ++ char *devname; /**< For /proc/interrupts */ ++ int if_version; /**< Highest interface version set */ ++ ++ /** \name Locks */ ++ /*@{ */ ++ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ ++ struct mutex struct_mutex; /**< For others */ ++ /*@} */ ++ ++ /** \name Usage Counters */ ++ /*@{ */ ++ int open_count; /**< Outstanding files open */ ++ atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ ++ atomic_t vma_count; /**< Outstanding vma areas open */ ++ int buf_use; /**< Buffers in use -- cannot alloc */ ++ atomic_t buf_alloc; /**< Buffer allocation in progress */ ++ /*@} */ ++ ++ /** \name Performance counters */ ++ /*@{ */ ++ unsigned long counters; ++ enum drm_stat_type types[15]; ++ atomic_t counts[15]; ++ /*@} */ ++ ++ struct list_head filelist; ++ ++ /** \name Memory management */ ++ /*@{ */ ++ struct list_head maplist; /**< Linked list of regions */ ++ int map_count; /**< Number of mappable regions */ ++ struct drm_open_hash map_hash; /**< User token hash table for maps */ ++ ++ /** \name Context handle management */ ++ /*@{ */ ++ struct list_head ctxlist; /**< Linked list of context handles */ ++ int ctx_count; /**< Number of context handles */ ++ struct mutex ctxlist_mutex; /**< For ctxlist */ ++ ++ struct idr ctx_idr; ++ ++ struct list_head vmalist; /**< List of vmas (for debugging) */ ++ ++ /*@} */ ++ ++ /** \name DMA queues (contexts) */ ++ /*@{ */ ++ int queue_count; /**< Number of active DMA queues */ ++ int queue_reserved; /**< Number of reserved DMA queues */ ++ int queue_slots; /**< Actual length of queuelist */ ++ struct drm_queue **queuelist; /**< Vector of pointers to DMA queues */ ++ struct drm_device_dma *dma; /**< Optional pointer for DMA support */ ++ /*@} */ ++ ++ /** \name Context support */ ++ /*@{ */ ++ int irq_enabled; /**< True if irq handler is enabled */ ++ __volatile__ long context_flag; /**< Context swapping flag */ ++ __volatile__ long interrupt_flag; /**< Interruption handler flag */ ++ __volatile__ long dma_flag; /**< DMA dispatch flag */ ++ wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ ++ int last_checked; /**< Last context checked for DMA */ ++ int last_context; /**< Last current context */ ++ unsigned long last_switch; /**< jiffies at last context switch */ ++ /*@} */ ++ ++ struct work_struct work; ++ /** \name VBLANK IRQ support */ ++ /*@{ */ ++ ++ /* ++ * At load time, disabling the vblank interrupt won't be allowed since ++ * old clients may not call the modeset ioctl and therefore misbehave. ++ * Once the modeset ioctl *has* been called though, we can safely ++ * disable them when unused. ++ */ ++ int vblank_disable_allowed; ++ ++ wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ ++ atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ ++ struct timeval *_vblank_time; /**< timestamp of current vblank_count (drivers must alloc right number of fields) */ ++ spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ ++ spinlock_t vbl_lock; ++ atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ ++ u32 *last_vblank; /* protected by dev->vbl_lock, used */ ++ /* for wraparound handling */ ++ int *vblank_enabled; /* so we don't call enable more than ++ once per disable */ ++ int *vblank_inmodeset; /* Display driver is setting mode */ ++ u32 *last_vblank_wait; /* Last vblank seqno waited per CRTC */ ++ struct timer_list vblank_disable_timer; ++ ++ u32 max_vblank_count; /**< size of vblank counter register */ ++ ++ /** ++ * List of events ++ */ ++ struct list_head vblank_event_list; ++ spinlock_t event_lock; ++ ++ /*@} */ ++ cycles_t ctx_start; ++ cycles_t lck_start; ++ ++ struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ ++ wait_queue_head_t buf_readers; /**< Processes waiting to read */ ++ wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ ++ ++ struct drm_agp_head *agp; /**< AGP data */ ++ ++ struct device *dev; /**< Device structure */ ++ struct pci_dev *pdev; /**< PCI device structure */ ++ int pci_vendor; /**< PCI vendor id */ ++ int pci_device; /**< PCI device id */ ++#ifdef __alpha__ ++ struct pci_controller *hose; ++#endif ++ ++ struct platform_device *platformdev; /**< Platform device struture */ ++ struct usb_device *usbdev; ++ ++ struct drm_sg_mem *sg; /**< Scatter gather memory */ ++ unsigned int num_crtcs; /**< Number of CRTCs on this device */ ++ void *dev_private; /**< device private data */ ++ void *mm_private; ++ struct address_space *dev_mapping; ++ struct drm_sigdata sigdata; /**< For block_all_signals */ ++ sigset_t sigmask; ++ ++ struct drm_driver *driver; ++ struct drm_local_map *agp_buffer_map; ++ unsigned int agp_buffer_token; ++ struct drm_minor *control; /**< Control node for card */ ++ struct drm_minor *primary; /**< render type primary screen head */ ++ ++ struct drm_mode_config mode_config; /**< Current mode config */ ++ ++ /** \name GEM information */ ++ /*@{ */ ++ spinlock_t object_name_lock; ++ struct idr object_name_idr; ++ /*@} */ ++ int switch_power_state; ++ ++ atomic_t unplugged; /* device has been unplugged or gone away */ ++}; ++ ++#define DRM_SWITCH_POWER_ON 0 ++#define DRM_SWITCH_POWER_OFF 1 ++#define DRM_SWITCH_POWER_CHANGING 2 ++ ++static __inline__ int drm_core_check_feature(struct drm_device *dev, ++ int feature) ++{ ++ return ((dev->driver->driver_features & feature) ? 1 : 0); ++} ++ ++static inline int drm_dev_to_irq(struct drm_device *dev) ++{ ++ return dev->driver->bus->get_irq(dev); ++} ++ ++ ++#if __OS_HAS_AGP ++static inline int drm_core_has_AGP(struct drm_device *dev) ++{ ++ return drm_core_check_feature(dev, DRIVER_USE_AGP); ++} ++#else ++#define drm_core_has_AGP(dev) (0) ++#endif ++ ++#if __OS_HAS_MTRR ++static inline int drm_core_has_MTRR(struct drm_device *dev) ++{ ++ return drm_core_check_feature(dev, DRIVER_USE_MTRR); ++} ++ ++#define DRM_MTRR_WC MTRR_TYPE_WRCOMB ++ ++static inline int drm_mtrr_add(unsigned long offset, unsigned long size, ++ unsigned int flags) ++{ ++ return mtrr_add(offset, size, flags, 1); ++} ++ ++static inline int drm_mtrr_del(int handle, unsigned long offset, ++ unsigned long size, unsigned int flags) ++{ ++ return mtrr_del(handle, offset, size); ++} ++ ++#else ++#define drm_core_has_MTRR(dev) (0) ++ ++#define DRM_MTRR_WC 0 ++ ++static inline int drm_mtrr_add(unsigned long offset, unsigned long size, ++ unsigned int flags) ++{ ++ return 0; ++} ++ ++static inline int drm_mtrr_del(int handle, unsigned long offset, ++ unsigned long size, unsigned int flags) ++{ ++ return 0; ++} ++#endif ++ ++static inline void drm_device_set_unplugged(struct drm_device *dev) ++{ ++ smp_wmb(); ++ atomic_set(&dev->unplugged, 1); ++} ++ ++static inline int drm_device_is_unplugged(struct drm_device *dev) ++{ ++ int ret = atomic_read(&dev->unplugged); ++ smp_rmb(); ++ return ret; ++} ++ ++/******************************************************************/ ++/** \name Internal function definitions */ ++/*@{*/ ++ ++ /* Driver support (drm_drv.h) */ ++extern long drm_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg); ++extern long drm_compat_ioctl(struct file *filp, ++ unsigned int cmd, unsigned long arg); ++extern int drm_lastclose(struct drm_device *dev); ++ ++ /* Device support (drm_fops.h) */ ++extern struct mutex drm_global_mutex; ++extern int drm_open(struct inode *inode, struct file *filp); ++extern int drm_stub_open(struct inode *inode, struct file *filp); ++extern int drm_fasync(int fd, struct file *filp, int on); ++extern ssize_t drm_read(struct file *filp, char __user *buffer, ++ size_t count, loff_t *offset); ++extern int drm_release(struct inode *inode, struct file *filp); ++ ++ /* Mapping support (drm_vm.h) */ ++extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); ++extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma); ++extern void drm_vm_open_locked(struct vm_area_struct *vma); ++extern void drm_vm_close_locked(struct vm_area_struct *vma); ++extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); ++ ++ /* Memory management support (drm_memory.h) */ ++#include "drm_memory.h" ++extern void drm_free_agp(DRM_AGP_MEM * handle, int pages); ++extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start); ++extern DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev, ++ struct page **pages, ++ unsigned long num_pages, ++ uint32_t gtt_offset, ++ uint32_t type); ++extern int drm_unbind_agp(DRM_AGP_MEM * handle); ++ ++ /* Misc. IOCTL support (drm_ioctl.h) */ ++extern int drm_irq_by_busid(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getunique(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_setunique(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getmap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getclient(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getstats(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getcap(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_setversion(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_noop(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++ /* Context IOCTL support (drm_context.h) */ ++extern int drm_resctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_addctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_modctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_switchctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_newctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_rmctx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern int drm_ctxbitmap_init(struct drm_device *dev); ++extern void drm_ctxbitmap_cleanup(struct drm_device *dev); ++extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle); ++ ++extern int drm_setsareactx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_getsareactx(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++ /* Authentication IOCTL support (drm_auth.h) */ ++extern int drm_getmagic(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_authmagic(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic); ++ ++/* Cache management (drm_cache.c) */ ++void drm_clflush_pages(struct page *pages[], unsigned long num_pages); ++ ++ /* Locking IOCTL support (drm_lock.h) */ ++extern int drm_lock(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_unlock(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context); ++extern void drm_idlelock_take(struct drm_lock_data *lock_data); ++extern void drm_idlelock_release(struct drm_lock_data *lock_data); ++ ++/* ++ * These are exported to drivers so that they can implement fencing using ++ * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. ++ */ ++ ++extern int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv); ++ ++ /* Buffer management support (drm_bufs.h) */ ++extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request); ++extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request); ++extern int drm_addmap(struct drm_device *dev, resource_size_t offset, ++ unsigned int size, enum drm_map_type type, ++ enum drm_map_flags flags, struct drm_local_map **map_ptr); ++extern int drm_addmap_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_rmmap(struct drm_device *dev, struct drm_local_map *map); ++extern int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map); ++extern int drm_rmmap_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_addbufs(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_infobufs(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_markbufs(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_freebufs(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_mapbufs(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_order(unsigned long size); ++ ++ /* DMA support (drm_dma.h) */ ++extern int drm_dma_setup(struct drm_device *dev); ++extern void drm_dma_takedown(struct drm_device *dev); ++extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf); ++extern void drm_core_reclaim_buffers(struct drm_device *dev, ++ struct drm_file *filp); ++ ++ /* IRQ support (drm_irq.h) */ ++extern int drm_control(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_irq_install(struct drm_device *dev); ++extern int drm_irq_uninstall(struct drm_device *dev); ++ ++extern int drm_vblank_init(struct drm_device *dev, int num_crtcs); ++extern int drm_wait_vblank(struct drm_device *dev, void *data, ++ struct drm_file *filp); ++extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); ++extern u32 drm_vblank_count(struct drm_device *dev, int crtc); ++extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, ++ struct timeval *vblanktime); ++extern bool drm_handle_vblank(struct drm_device *dev, int crtc); ++extern int drm_vblank_get(struct drm_device *dev, int crtc); ++extern void drm_vblank_put(struct drm_device *dev, int crtc); ++extern void drm_vblank_off(struct drm_device *dev, int crtc); ++extern void drm_vblank_cleanup(struct drm_device *dev); ++extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, ++ struct timeval *tvblank, unsigned flags); ++extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, ++ int crtc, int *max_error, ++ struct timeval *vblank_time, ++ unsigned flags, ++ struct drm_crtc *refcrtc); ++extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); ++ ++extern bool ++drm_mode_parse_command_line_for_connector(const char *mode_option, ++ struct drm_connector *connector, ++ struct drm_cmdline_mode *mode); ++ ++extern struct drm_display_mode * ++drm_mode_create_from_cmdline_mode(struct drm_device *dev, ++ struct drm_cmdline_mode *cmd); ++ ++/* Modesetting support */ ++extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc); ++extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc); ++extern int drm_modeset_ctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++ /* AGP/GART support (drm_agpsupport.h) */ ++extern struct drm_agp_head *drm_agp_init(struct drm_device *dev); ++extern int drm_agp_acquire(struct drm_device *dev); ++extern int drm_agp_acquire_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_release(struct drm_device *dev); ++extern int drm_agp_release_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode); ++extern int drm_agp_enable_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info); ++extern int drm_agp_info_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request); ++extern int drm_agp_alloc_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request); ++extern int drm_agp_free_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request); ++extern int drm_agp_unbind_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request); ++extern int drm_agp_bind_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++ /* Stub support (drm_stub.h) */ ++extern int drm_setmaster_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_dropmaster_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++struct drm_master *drm_master_create(struct drm_minor *minor); ++extern struct drm_master *drm_master_get(struct drm_master *master); ++extern void drm_master_put(struct drm_master **master); ++ ++extern void drm_put_dev(struct drm_device *dev); ++extern int drm_put_minor(struct drm_minor **minor); ++extern void drm_unplug_dev(struct drm_device *dev); ++extern unsigned int drm_debug; ++ ++extern unsigned int drm_vblank_offdelay; ++extern unsigned int drm_timestamp_precision; ++ ++extern struct class *drm_class; ++extern struct proc_dir_entry *drm_proc_root; ++extern struct dentry *drm_debugfs_root; ++ ++extern struct idr drm_minors_idr; ++ ++extern struct drm_local_map *drm_getsarea(struct drm_device *dev); ++ ++ /* Proc support (drm_proc.h) */ ++extern int drm_proc_init(struct drm_minor *minor, int minor_id, ++ struct proc_dir_entry *root); ++extern int drm_proc_cleanup(struct drm_minor *minor, struct proc_dir_entry *root); ++ ++ /* Debugfs support */ ++#if defined(CONFIG_DEBUG_FS) ++extern int drm_debugfs_init(struct drm_minor *minor, int minor_id, ++ struct dentry *root); ++extern int drm_debugfs_create_files(struct drm_info_list *files, int count, ++ struct dentry *root, struct drm_minor *minor); ++extern int drm_debugfs_remove_files(struct drm_info_list *files, int count, ++ struct drm_minor *minor); ++extern int drm_debugfs_cleanup(struct drm_minor *minor); ++#endif ++ ++ /* Info file support */ ++extern int drm_name_info(struct seq_file *m, void *data); ++extern int drm_vm_info(struct seq_file *m, void *data); ++extern int drm_queues_info(struct seq_file *m, void *data); ++extern int drm_bufs_info(struct seq_file *m, void *data); ++extern int drm_vblank_info(struct seq_file *m, void *data); ++extern int drm_clients_info(struct seq_file *m, void* data); ++extern int drm_gem_name_info(struct seq_file *m, void *data); ++ ++ ++extern int drm_gem_prime_handle_to_fd(struct drm_device *dev, ++ struct drm_file *file_priv, uint32_t handle, uint32_t flags, ++ int *prime_fd); ++extern int drm_gem_prime_fd_to_handle(struct drm_device *dev, ++ struct drm_file *file_priv, int prime_fd, uint32_t *handle); ++ ++extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages); ++extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg); ++ ++ ++void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv); ++void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv); ++int drm_prime_add_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle); ++int drm_prime_lookup_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle); ++void drm_prime_remove_imported_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf); ++ ++int drm_prime_add_dma_buf(struct drm_device *dev, struct drm_gem_object *obj); ++int drm_prime_lookup_obj(struct drm_device *dev, struct dma_buf *buf, ++ struct drm_gem_object **obj); ++ ++#if DRM_DEBUG_CODE ++extern int drm_vma_info(struct seq_file *m, void *data); ++#endif ++ ++ /* Scatter Gather Support (drm_scatter.h) */ ++extern void drm_sg_cleanup(struct drm_sg_mem * entry); ++extern int drm_sg_alloc_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request); ++extern int drm_sg_free(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++ ++ /* ATI PCIGART support (ati_pcigart.h) */ ++extern int drm_ati_pcigart_init(struct drm_device *dev, ++ struct drm_ati_pcigart_info * gart_info); ++extern int drm_ati_pcigart_cleanup(struct drm_device *dev, ++ struct drm_ati_pcigart_info * gart_info); ++ ++extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size, ++ size_t align); ++extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); ++extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah); ++ ++ /* sysfs support (drm_sysfs.c) */ ++struct drm_sysfs_class; ++extern struct class *drm_sysfs_create(struct module *owner, char *name); ++extern void drm_sysfs_destroy(void); ++extern int drm_sysfs_device_add(struct drm_minor *minor); ++extern void drm_sysfs_hotplug_event(struct drm_device *dev); ++extern void drm_sysfs_device_remove(struct drm_minor *minor); ++extern char *drm_get_connector_status_name(enum drm_connector_status status); ++extern int drm_sysfs_connector_add(struct drm_connector *connector); ++extern void drm_sysfs_connector_remove(struct drm_connector *connector); ++ ++/* Graphics Execution Manager library functions (drm_gem.c) */ ++int drm_gem_init(struct drm_device *dev); ++void drm_gem_destroy(struct drm_device *dev); ++void drm_gem_object_release(struct drm_gem_object *obj); ++void drm_gem_object_free(struct kref *kref); ++struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev, ++ size_t size); ++int drm_gem_object_init(struct drm_device *dev, ++ struct drm_gem_object *obj, size_t size); ++int drm_gem_private_object_init(struct drm_device *dev, ++ struct drm_gem_object *obj, size_t size); ++void drm_gem_object_handle_free(struct drm_gem_object *obj); ++void drm_gem_vm_open(struct vm_area_struct *vma); ++void drm_gem_vm_close(struct vm_area_struct *vma); ++int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); ++ ++#include "drm_global.h" ++ ++static inline void ++drm_gem_object_reference(struct drm_gem_object *obj) ++{ ++ kref_get(&obj->refcount); ++} ++ ++static inline void ++drm_gem_object_unreference(struct drm_gem_object *obj) ++{ ++ if (obj != NULL) ++ kref_put(&obj->refcount, drm_gem_object_free); ++} ++ ++static inline void ++drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) ++{ ++ if (obj != NULL) { ++ struct drm_device *dev = obj->dev; ++ mutex_lock(&dev->struct_mutex); ++ kref_put(&obj->refcount, drm_gem_object_free); ++ mutex_unlock(&dev->struct_mutex); ++ } ++} ++ ++int drm_gem_handle_create(struct drm_file *file_priv, ++ struct drm_gem_object *obj, ++ u32 *handlep); ++int drm_gem_handle_delete(struct drm_file *filp, u32 handle); ++ ++static inline void ++drm_gem_object_handle_reference(struct drm_gem_object *obj) ++{ ++ drm_gem_object_reference(obj); ++ atomic_inc(&obj->handle_count); ++} ++ ++static inline void ++drm_gem_object_handle_unreference(struct drm_gem_object *obj) ++{ ++ if (obj == NULL) ++ return; ++ ++ if (atomic_read(&obj->handle_count) == 0) ++ return; ++ /* ++ * Must bump handle count first as this may be the last ++ * ref, in which case the object would disappear before we ++ * checked for a name ++ */ ++ if (atomic_dec_and_test(&obj->handle_count)) ++ drm_gem_object_handle_free(obj); ++ drm_gem_object_unreference(obj); ++} ++ ++static inline void ++drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) ++{ ++ if (obj == NULL) ++ return; ++ ++ if (atomic_read(&obj->handle_count) == 0) ++ return; ++ ++ /* ++ * Must bump handle count first as this may be the last ++ * ref, in which case the object would disappear before we ++ * checked for a name ++ */ ++ ++ if (atomic_dec_and_test(&obj->handle_count)) ++ drm_gem_object_handle_free(obj); ++ drm_gem_object_unreference_unlocked(obj); ++} ++ ++void drm_gem_free_mmap_offset(struct drm_gem_object *obj); ++int drm_gem_create_mmap_offset(struct drm_gem_object *obj); ++ ++struct drm_gem_object *drm_gem_object_lookup(struct drm_device *dev, ++ struct drm_file *filp, ++ u32 handle); ++int drm_gem_close_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int drm_gem_flink_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++int drm_gem_open_ioctl(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++void drm_gem_open(struct drm_device *dev, struct drm_file *file_private); ++void drm_gem_release(struct drm_device *dev, struct drm_file *file_private); ++ ++extern void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev); ++extern void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev); ++extern void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev); ++ ++static __inline__ struct drm_local_map *drm_core_findmap(struct drm_device *dev, ++ unsigned int token) ++{ ++ struct drm_map_list *_entry; ++ list_for_each_entry(_entry, &dev->maplist, head) ++ if (_entry->user_token == token) ++ return _entry->map; ++ return NULL; ++} ++ ++static __inline__ void drm_core_dropmap(struct drm_local_map *map) ++{ ++} ++ ++#include "drm_mem_util.h" ++ ++extern int drm_fill_in_dev(struct drm_device *dev, ++ const struct pci_device_id *ent, ++ struct drm_driver *driver); ++int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type); ++/*@}*/ ++ ++/* PCI section */ ++static __inline__ int drm_pci_device_is_agp(struct drm_device *dev) ++{ ++ if (dev->driver->device_is_agp != NULL) { ++ int err = (*dev->driver->device_is_agp) (dev); ++ ++ if (err != 2) { ++ return err; ++ } ++ } ++ ++ return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP); ++} ++ ++extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver); ++extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver); ++extern int drm_get_pci_dev(struct pci_dev *pdev, ++ const struct pci_device_id *ent, ++ struct drm_driver *driver); ++ ++ ++/* platform section */ ++extern int drm_platform_init(struct drm_driver *driver, struct platform_device *platform_device); ++extern void drm_platform_exit(struct drm_driver *driver, struct platform_device *platform_device); ++ ++extern int drm_get_platform_dev(struct platform_device *pdev, ++ struct drm_driver *driver); ++ ++/* returns true if currently okay to sleep */ ++static __inline__ bool drm_can_sleep(void) ++{ ++ if (in_atomic() || in_dbg_master() || irqs_disabled()) ++ return false; ++ return true; ++} ++ ++#endif /* __KERNEL__ */ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_buffer.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_buffer.h +new file mode 100644 +index 0000000..322dbff +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_buffer.h +@@ -0,0 +1,148 @@ ++/************************************************************************** ++ * ++ * Copyright 2010 Pauli Nieminen. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * ++ **************************************************************************/ ++/* ++ * Multipart buffer for coping data which is larger than the page size. ++ * ++ * Authors: ++ * Pauli Nieminen ++ */ ++ ++#ifndef _DRM_BUFFER_H_ ++#define _DRM_BUFFER_H_ ++ ++#include "drmP.h" ++ ++struct drm_buffer { ++ int iterator; ++ int size; ++ char *data[]; ++}; ++ ++ ++/** ++ * Return the index of page that buffer is currently pointing at. ++ */ ++static inline int drm_buffer_page(struct drm_buffer *buf) ++{ ++ return buf->iterator / PAGE_SIZE; ++} ++/** ++ * Return the index of the current byte in the page ++ */ ++static inline int drm_buffer_index(struct drm_buffer *buf) ++{ ++ return buf->iterator & (PAGE_SIZE - 1); ++} ++/** ++ * Return number of bytes that is left to process ++ */ ++static inline int drm_buffer_unprocessed(struct drm_buffer *buf) ++{ ++ return buf->size - buf->iterator; ++} ++ ++/** ++ * Advance the buffer iterator number of bytes that is given. ++ */ ++static inline void drm_buffer_advance(struct drm_buffer *buf, int bytes) ++{ ++ buf->iterator += bytes; ++} ++ ++/** ++ * Allocate the drm buffer object. ++ * ++ * buf: A pointer to a pointer where the object is stored. ++ * size: The number of bytes to allocate. ++ */ ++extern int drm_buffer_alloc(struct drm_buffer **buf, int size); ++ ++/** ++ * Copy the user data to the begin of the buffer and reset the processing ++ * iterator. ++ * ++ * user_data: A pointer the data that is copied to the buffer. ++ * size: The Number of bytes to copy. ++ */ ++extern int drm_buffer_copy_from_user(struct drm_buffer *buf, ++ void __user *user_data, int size); ++ ++/** ++ * Free the drm buffer object ++ */ ++extern void drm_buffer_free(struct drm_buffer *buf); ++ ++/** ++ * Read an object from buffer that may be split to multiple parts. If object ++ * is not split function just returns the pointer to object in buffer. But in ++ * case of split object data is copied to given stack object that is suplied ++ * by caller. ++ * ++ * The processing location of the buffer is also advanced to the next byte ++ * after the object. ++ * ++ * objsize: The size of the objet in bytes. ++ * stack_obj: A pointer to a memory location where object can be copied. ++ */ ++extern void *drm_buffer_read_object(struct drm_buffer *buf, ++ int objsize, void *stack_obj); ++ ++/** ++ * Returns the pointer to the dword which is offset number of elements from the ++ * current processing location. ++ * ++ * Caller must make sure that dword is not split in the buffer. This ++ * requirement is easily met if all the sizes of objects in buffer are ++ * multiples of dword and PAGE_SIZE is multiple dword. ++ * ++ * Call to this function doesn't change the processing location. ++ * ++ * offset: The index of the dword relative to the internat iterator. ++ */ ++static inline void *drm_buffer_pointer_to_dword(struct drm_buffer *buffer, ++ int offset) ++{ ++ int iter = buffer->iterator + offset * 4; ++ return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)]; ++} ++/** ++ * Returns the pointer to the dword which is offset number of elements from ++ * the current processing location. ++ * ++ * Call to this function doesn't change the processing location. ++ * ++ * offset: The index of the byte relative to the internat iterator. ++ */ ++static inline void *drm_buffer_pointer_to_byte(struct drm_buffer *buffer, ++ int offset) ++{ ++ int iter = buffer->iterator + offset; ++ return &buffer->data[iter / PAGE_SIZE][iter & (PAGE_SIZE - 1)]; ++} ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_cache.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_cache.h +new file mode 100644 +index 0000000..7bfb063 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_cache.h +@@ -0,0 +1,38 @@ ++/************************************************************************** ++ * ++ * Copyright 2009 Red Hat Inc. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * ++ **************************************************************************/ ++/* ++ * Authors: ++ * Dave Airlie ++ */ ++ ++#ifndef _DRM_CACHE_H_ ++#define _DRM_CACHE_H_ ++ ++void drm_clflush_pages(struct page *pages[], unsigned long num_pages); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_core.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_core.h +new file mode 100644 +index 0000000..4e75238 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_core.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright 2004 Jon Smirl ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sub license, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ * DEALINGS IN THE SOFTWARE. ++ */ ++#define CORE_AUTHOR "Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl" ++ ++#define CORE_NAME "drm" ++#define CORE_DESC "DRM shared core routines" ++#define CORE_DATE "20060810" ++ ++#define DRM_IF_MAJOR 1 ++#define DRM_IF_MINOR 4 ++ ++#define CORE_MAJOR 1 ++#define CORE_MINOR 1 ++#define CORE_PATCHLEVEL 0 +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc.h +new file mode 100644 +index 0000000..e250eda +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc.h +@@ -0,0 +1,1029 @@ ++/* ++ * Copyright © 2006 Keith Packard ++ * Copyright © 2007-2008 Dave Airlie ++ * Copyright © 2007-2008 Intel Corporation ++ * Jesse Barnes ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef __DRM_CRTC_H__ ++#define __DRM_CRTC_H__ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++struct drm_device; ++struct drm_mode_set; ++struct drm_framebuffer; ++ ++ ++#define DRM_MODE_OBJECT_CRTC 0xcccccccc ++#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 ++#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0 ++#define DRM_MODE_OBJECT_MODE 0xdededede ++#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0 ++#define DRM_MODE_OBJECT_FB 0xfbfbfbfb ++#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb ++#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee ++ ++struct drm_mode_object { ++ uint32_t id; ++ uint32_t type; ++}; ++ ++/* ++ * Note on terminology: here, for brevity and convenience, we refer to connector ++ * control chips as 'CRTCs'. They can control any type of connector, VGA, LVDS, ++ * DVI, etc. And 'screen' refers to the whole of the visible display, which ++ * may span multiple monitors (and therefore multiple CRTC and connector ++ * structures). ++ */ ++ ++enum drm_mode_status { ++ MODE_OK = 0, /* Mode OK */ ++ MODE_HSYNC, /* hsync out of range */ ++ MODE_VSYNC, /* vsync out of range */ ++ MODE_H_ILLEGAL, /* mode has illegal horizontal timings */ ++ MODE_V_ILLEGAL, /* mode has illegal horizontal timings */ ++ MODE_BAD_WIDTH, /* requires an unsupported linepitch */ ++ MODE_NOMODE, /* no mode with a matching name */ ++ MODE_NO_INTERLACE, /* interlaced mode not supported */ ++ MODE_NO_DBLESCAN, /* doublescan mode not supported */ ++ MODE_NO_VSCAN, /* multiscan mode not supported */ ++ MODE_MEM, /* insufficient video memory */ ++ MODE_VIRTUAL_X, /* mode width too large for specified virtual size */ ++ MODE_VIRTUAL_Y, /* mode height too large for specified virtual size */ ++ MODE_MEM_VIRT, /* insufficient video memory given virtual size */ ++ MODE_NOCLOCK, /* no fixed clock available */ ++ MODE_CLOCK_HIGH, /* clock required is too high */ ++ MODE_CLOCK_LOW, /* clock required is too low */ ++ MODE_CLOCK_RANGE, /* clock/mode isn't in a ClockRange */ ++ MODE_BAD_HVALUE, /* horizontal timing was out of range */ ++ MODE_BAD_VVALUE, /* vertical timing was out of range */ ++ MODE_BAD_VSCAN, /* VScan value out of range */ ++ MODE_HSYNC_NARROW, /* horizontal sync too narrow */ ++ MODE_HSYNC_WIDE, /* horizontal sync too wide */ ++ MODE_HBLANK_NARROW, /* horizontal blanking too narrow */ ++ MODE_HBLANK_WIDE, /* horizontal blanking too wide */ ++ MODE_VSYNC_NARROW, /* vertical sync too narrow */ ++ MODE_VSYNC_WIDE, /* vertical sync too wide */ ++ MODE_VBLANK_NARROW, /* vertical blanking too narrow */ ++ MODE_VBLANK_WIDE, /* vertical blanking too wide */ ++ MODE_PANEL, /* exceeds panel dimensions */ ++ MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */ ++ MODE_ONE_WIDTH, /* only one width is supported */ ++ MODE_ONE_HEIGHT, /* only one height is supported */ ++ MODE_ONE_SIZE, /* only one resolution is supported */ ++ MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ ++ MODE_UNVERIFIED = -3, /* mode needs to reverified */ ++ MODE_BAD = -2, /* unspecified reason */ ++ MODE_ERROR = -1 /* error condition */ ++}; ++ ++#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \ ++ DRM_MODE_TYPE_CRTC_C) ++ ++#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \ ++ .name = nm, .status = 0, .type = (t), .clock = (c), \ ++ .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \ ++ .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \ ++ .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ ++ .vscan = (vs), .flags = (f), .vrefresh = 0 ++ ++#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ ++ ++struct drm_display_mode { ++ /* Header */ ++ struct list_head head; ++ struct drm_mode_object base; ++ ++ char name[DRM_DISPLAY_MODE_LEN]; ++ ++ enum drm_mode_status status; ++ unsigned int type; ++ ++ /* Proposed mode values */ ++ int clock; /* in kHz */ ++ int hdisplay; ++ int hsync_start; ++ int hsync_end; ++ int htotal; ++ int hskew; ++ int vdisplay; ++ int vsync_start; ++ int vsync_end; ++ int vtotal; ++ int vscan; ++ unsigned int flags; ++ ++ /* Addressable image size (may be 0 for projectors, etc.) */ ++ int width_mm; ++ int height_mm; ++ ++ /* Actual mode we give to hw */ ++ int clock_index; ++ int synth_clock; ++ int crtc_hdisplay; ++ int crtc_hblank_start; ++ int crtc_hblank_end; ++ int crtc_hsync_start; ++ int crtc_hsync_end; ++ int crtc_htotal; ++ int crtc_hskew; ++ int crtc_vdisplay; ++ int crtc_vblank_start; ++ int crtc_vblank_end; ++ int crtc_vsync_start; ++ int crtc_vsync_end; ++ int crtc_vtotal; ++ int crtc_hadjusted; ++ int crtc_vadjusted; ++ ++ /* Driver private mode info */ ++ int private_size; ++ int *private; ++ int private_flags; ++ ++ int vrefresh; /* in Hz */ ++ int hsync; /* in kHz */ ++}; ++ ++enum drm_connector_status { ++ connector_status_connected = 1, ++ connector_status_disconnected = 2, ++ connector_status_unknown = 3, ++}; ++ ++enum subpixel_order { ++ SubPixelUnknown = 0, ++ SubPixelHorizontalRGB, ++ SubPixelHorizontalBGR, ++ SubPixelVerticalRGB, ++ SubPixelVerticalBGR, ++ SubPixelNone, ++}; ++ ++#define DRM_COLOR_FORMAT_RGB444 (1<<0) ++#define DRM_COLOR_FORMAT_YCRCB444 (1<<1) ++#define DRM_COLOR_FORMAT_YCRCB422 (1<<2) ++/* ++ * Describes a given display (e.g. CRT or flat panel) and its limitations. ++ */ ++struct drm_display_info { ++ char name[DRM_DISPLAY_INFO_LEN]; ++ ++ /* Physical size */ ++ unsigned int width_mm; ++ unsigned int height_mm; ++ ++ /* Clock limits FIXME: storage format */ ++ unsigned int min_vfreq, max_vfreq; ++ unsigned int min_hfreq, max_hfreq; ++ unsigned int pixel_clock; ++ unsigned int bpc; ++ ++ enum subpixel_order subpixel_order; ++ u32 color_formats; ++ ++ u8 cea_rev; ++ ++ char *raw_edid; /* if any */ ++}; ++ ++struct drm_framebuffer_funcs { ++ void (*destroy)(struct drm_framebuffer *framebuffer); ++ int (*create_handle)(struct drm_framebuffer *fb, ++ struct drm_file *file_priv, ++ unsigned int *handle); ++ /** ++ * Optinal callback for the dirty fb ioctl. ++ * ++ * Userspace can notify the driver via this callback ++ * that a area of the framebuffer has changed and should ++ * be flushed to the display hardware. ++ * ++ * See documentation in drm_mode.h for the struct ++ * drm_mode_fb_dirty_cmd for more information as all ++ * the semantics and arguments have a one to one mapping ++ * on this function. ++ */ ++ int (*dirty)(struct drm_framebuffer *framebuffer, ++ struct drm_file *file_priv, unsigned flags, ++ unsigned color, struct drm_clip_rect *clips, ++ unsigned num_clips); ++}; ++ ++struct drm_framebuffer { ++ struct drm_device *dev; ++ struct list_head head; ++ struct drm_mode_object base; ++ const struct drm_framebuffer_funcs *funcs; ++ unsigned int pitches[4]; ++ unsigned int offsets[4]; ++ unsigned int width; ++ unsigned int height; ++ /* depth can be 15 or 16 */ ++ unsigned int depth; ++ int bits_per_pixel; ++ int flags; ++ uint32_t pixel_format; /* fourcc format */ ++ struct list_head filp_head; ++ /* if you are using the helper */ ++ void *helper_private; ++}; ++ ++struct drm_property_blob { ++ struct drm_mode_object base; ++ struct list_head head; ++ unsigned int length; ++ unsigned char data[]; ++}; ++ ++struct drm_property_enum { ++ uint64_t value; ++ struct list_head head; ++ char name[DRM_PROP_NAME_LEN]; ++}; ++ ++struct drm_property { ++ struct list_head head; ++ struct drm_mode_object base; ++ uint32_t flags; ++ char name[DRM_PROP_NAME_LEN]; ++ uint32_t num_values; ++ uint64_t *values; ++ ++ struct list_head enum_blob_list; ++}; ++ ++struct drm_crtc; ++struct drm_connector; ++struct drm_encoder; ++struct drm_pending_vblank_event; ++struct drm_plane; ++ ++/** ++ * drm_crtc_funcs - control CRTCs for a given device ++ * @reset: reset CRTC after state has been invalidate (e.g. resume) ++ * @dpms: control display power levels ++ * @save: save CRTC state ++ * @resore: restore CRTC state ++ * @lock: lock the CRTC ++ * @unlock: unlock the CRTC ++ * @shadow_allocate: allocate shadow pixmap ++ * @shadow_create: create shadow pixmap for rotation support ++ * @shadow_destroy: free shadow pixmap ++ * @mode_fixup: fixup proposed mode ++ * @mode_set: set the desired mode on the CRTC ++ * @gamma_set: specify color ramp for CRTC ++ * @destroy: deinit and free object. ++ * ++ * The drm_crtc_funcs structure is the central CRTC management structure ++ * in the DRM. Each CRTC controls one or more connectors (note that the name ++ * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. ++ * connectors, not just CRTs). ++ * ++ * Each driver is responsible for filling out this structure at startup time, ++ * in addition to providing other modesetting features, like i2c and DDC ++ * bus accessors. ++ */ ++struct drm_crtc_funcs { ++ /* Save CRTC state */ ++ void (*save)(struct drm_crtc *crtc); /* suspend? */ ++ /* Restore CRTC state */ ++ void (*restore)(struct drm_crtc *crtc); /* resume? */ ++ /* Reset CRTC state */ ++ void (*reset)(struct drm_crtc *crtc); ++ ++ /* cursor controls */ ++ int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, ++ uint32_t handle, uint32_t width, uint32_t height); ++ int (*cursor_move)(struct drm_crtc *crtc, int x, int y); ++ ++ /* Set gamma on the CRTC */ ++ void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, ++ uint32_t start, uint32_t size); ++ /* Object destroy routine */ ++ void (*destroy)(struct drm_crtc *crtc); ++ ++ int (*set_config)(struct drm_mode_set *set); ++ ++ /* ++ * Flip to the given framebuffer. This implements the page ++ * flip ioctl described in drm_mode.h, specifically, the ++ * implementation must return immediately and block all ++ * rendering to the current fb until the flip has completed. ++ * If userspace set the event flag in the ioctl, the event ++ * argument will point to an event to send back when the flip ++ * completes, otherwise it will be NULL. ++ */ ++ int (*page_flip)(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, ++ struct drm_pending_vblank_event *event); ++}; ++ ++/** ++ * drm_crtc - central CRTC control structure ++ * @dev: parent DRM device ++ * @head: list management ++ * @base: base KMS object for ID tracking etc. ++ * @enabled: is this CRTC enabled? ++ * @mode: current mode timings ++ * @hwmode: mode timings as programmed to hw regs ++ * @x: x position on screen ++ * @y: y position on screen ++ * @funcs: CRTC control functions ++ * @gamma_size: size of gamma ramp ++ * @gamma_store: gamma ramp values ++ * @framedur_ns: precise frame timing ++ * @framedur_ns: precise line timing ++ * @pixeldur_ns: precise pixel timing ++ * @helper_private: mid-layer private data ++ * ++ * Each CRTC may have one or more connectors associated with it. This structure ++ * allows the CRTC to be controlled. ++ */ ++struct drm_crtc { ++ struct drm_device *dev; ++ struct list_head head; ++ ++ struct drm_mode_object base; ++ ++ /* framebuffer the connector is currently bound to */ ++ struct drm_framebuffer *fb; ++ ++ bool enabled; ++ ++ /* Requested mode from modesetting. */ ++ struct drm_display_mode mode; ++ ++ /* Programmed mode in hw, after adjustments for encoders, ++ * crtc, panel scaling etc. Needed for timestamping etc. ++ */ ++ struct drm_display_mode hwmode; ++ ++ int x, y; ++ const struct drm_crtc_funcs *funcs; ++ ++ /* CRTC gamma size for reporting to userspace */ ++ uint32_t gamma_size; ++ uint16_t *gamma_store; ++ ++ /* Constants needed for precise vblank and swap timestamping. */ ++ s64 framedur_ns, linedur_ns, pixeldur_ns; ++ ++ /* if you are using the helper */ ++ void *helper_private; ++}; ++ ++ ++/** ++ * drm_connector_funcs - control connectors on a given device ++ * @dpms: set power state (see drm_crtc_funcs above) ++ * @save: save connector state ++ * @restore: restore connector state ++ * @reset: reset connector after state has been invalidate (e.g. resume) ++ * @mode_valid: is this mode valid on the given connector? ++ * @mode_fixup: try to fixup proposed mode for this connector ++ * @mode_set: set this mode ++ * @detect: is this connector active? ++ * @get_modes: get mode list for this connector ++ * @set_property: property for this connector may need update ++ * @destroy: make object go away ++ * @force: notify the driver the connector is forced on ++ * ++ * Each CRTC may have one or more connectors attached to it. The functions ++ * below allow the core DRM code to control connectors, enumerate available modes, ++ * etc. ++ */ ++struct drm_connector_funcs { ++ void (*dpms)(struct drm_connector *connector, int mode); ++ void (*save)(struct drm_connector *connector); ++ void (*restore)(struct drm_connector *connector); ++ void (*reset)(struct drm_connector *connector); ++ ++ /* Check to see if anything is attached to the connector. ++ * @force is set to false whilst polling, true when checking the ++ * connector due to user request. @force can be used by the driver ++ * to avoid expensive, destructive operations during automated ++ * probing. ++ */ ++ enum drm_connector_status (*detect)(struct drm_connector *connector, ++ bool force); ++ int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); ++ int (*set_property)(struct drm_connector *connector, struct drm_property *property, ++ uint64_t val); ++ void (*destroy)(struct drm_connector *connector); ++ void (*force)(struct drm_connector *connector); ++}; ++ ++/** ++ * drm_encoder_funcs - encoder controls ++ * @reset: reset state (e.g. at init or resume time) ++ * @destroy: cleanup and free associated data ++ * ++ * Encoders sit between CRTCs and connectors. ++ */ ++struct drm_encoder_funcs { ++ void (*reset)(struct drm_encoder *encoder); ++ void (*destroy)(struct drm_encoder *encoder); ++}; ++ ++#define DRM_CONNECTOR_MAX_UMODES 16 ++#define DRM_CONNECTOR_MAX_PROPERTY 16 ++#define DRM_CONNECTOR_LEN 32 ++#define DRM_CONNECTOR_MAX_ENCODER 3 ++ ++/** ++ * drm_encoder - central DRM encoder structure ++ * @dev: parent DRM device ++ * @head: list management ++ * @base: base KMS object ++ * @encoder_type: one of the %DRM_MODE_ENCODER_ types in drm_mode.h ++ * @possible_crtcs: bitmask of potential CRTC bindings ++ * @possible_clones: bitmask of potential sibling encoders for cloning ++ * @crtc: currently bound CRTC ++ * @funcs: control functions ++ * @helper_private: mid-layer private data ++ * ++ * CRTCs drive pixels to encoders, which convert them into signals ++ * appropriate for a given connector or set of connectors. ++ */ ++struct drm_encoder { ++ struct drm_device *dev; ++ struct list_head head; ++ ++ struct drm_mode_object base; ++ int encoder_type; ++ uint32_t possible_crtcs; ++ uint32_t possible_clones; ++ ++ struct drm_crtc *crtc; ++ const struct drm_encoder_funcs *funcs; ++ void *helper_private; ++}; ++ ++enum drm_connector_force { ++ DRM_FORCE_UNSPECIFIED, ++ DRM_FORCE_OFF, ++ DRM_FORCE_ON, /* force on analog part normally */ ++ DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ ++}; ++ ++/* should we poll this connector for connects and disconnects */ ++/* hot plug detectable */ ++#define DRM_CONNECTOR_POLL_HPD (1 << 0) ++/* poll for connections */ ++#define DRM_CONNECTOR_POLL_CONNECT (1 << 1) ++/* can cleanly poll for disconnections without flickering the screen */ ++/* DACs should rarely do this without a lot of testing */ ++#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) ++ ++#define MAX_ELD_BYTES 128 ++ ++/** ++ * drm_connector - central DRM connector control structure ++ * @dev: parent DRM device ++ * @kdev: kernel device for sysfs attributes ++ * @attr: sysfs attributes ++ * @head: list management ++ * @base: base KMS object ++ * @connector_type: one of the %DRM_MODE_CONNECTOR_ types from drm_mode.h ++ * @connector_type_id: index into connector type enum ++ * @interlace_allowed: can this connector handle interlaced modes? ++ * @doublescan_allowed: can this connector handle doublescan? ++ * @modes: modes available on this connector (from fill_modes() + user) ++ * @status: one of the drm_connector_status enums (connected, not, or unknown) ++ * @probed_modes: list of modes derived directly from the display ++ * @display_info: information about attached display (e.g. from EDID) ++ * @funcs: connector control functions ++ * @user_modes: user added mode list ++ * @edid_blob_ptr: DRM property containing EDID if present ++ * @property_ids: property tracking for this connector ++ * @property_values: value pointers or data for properties ++ * @polled: a %DRM_CONNECTOR_POLL_ value for core driven polling ++ * @dpms: current dpms state ++ * @helper_private: mid-layer private data ++ * @force: a %DRM_FORCE_ state for forced mode sets ++ * @encoder_ids: valid encoders for this connector ++ * @encoder: encoder driving this connector, if any ++ * @eld: EDID-like data, if present ++ * @dvi_dual: dual link DVI, if found ++ * @max_tmds_clock: max clock rate, if found ++ * @latency_present: AV delay info from ELD, if found ++ * @video_latency: video latency info from ELD, if found ++ * @audio_latency: audio latency info from ELD, if found ++ * @null_edid_counter: track sinks that give us all zeros for the EDID ++ * ++ * Each connector may be connected to one or more CRTCs, or may be clonable by ++ * another connector if they can share a CRTC. Each connector also has a specific ++ * position in the broader display (referred to as a 'screen' though it could ++ * span multiple monitors). ++ */ ++struct drm_connector { ++ struct drm_device *dev; ++ struct device kdev; ++ struct device_attribute *attr; ++ struct list_head head; ++ ++ struct drm_mode_object base; ++ ++ int connector_type; ++ int connector_type_id; ++ bool interlace_allowed; ++ bool doublescan_allowed; ++ struct list_head modes; /* list of modes on this connector */ ++ ++ enum drm_connector_status status; ++ ++ /* these are modes added by probing with DDC or the BIOS */ ++ struct list_head probed_modes; ++ ++ struct drm_display_info display_info; ++ const struct drm_connector_funcs *funcs; ++ ++ struct list_head user_modes; ++ struct drm_property_blob *edid_blob_ptr; ++ u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; ++ uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; ++ ++ uint8_t polled; /* DRM_CONNECTOR_POLL_* */ ++ ++ /* requested DPMS state */ ++ int dpms; ++ ++ void *helper_private; ++ ++ /* forced on connector */ ++ enum drm_connector_force force; ++ uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; ++ struct drm_encoder *encoder; /* currently active encoder */ ++ ++ /* EDID bits */ ++ uint8_t eld[MAX_ELD_BYTES]; ++ bool dvi_dual; ++ int max_tmds_clock; /* in MHz */ ++ bool latency_present[2]; ++ int video_latency[2]; /* [0]: progressive, [1]: interlaced */ ++ int audio_latency[2]; ++ int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */ ++}; ++ ++/** ++ * drm_plane_funcs - driver plane control functions ++ * @update_plane: update the plane configuration ++ * @disable_plane: shut down the plane ++ * @destroy: clean up plane resources ++ */ ++struct drm_plane_funcs { ++ int (*update_plane)(struct drm_plane *plane, ++ struct drm_crtc *crtc, struct drm_framebuffer *fb, ++ int crtc_x, int crtc_y, ++ unsigned int crtc_w, unsigned int crtc_h, ++ uint32_t src_x, uint32_t src_y, ++ uint32_t src_w, uint32_t src_h); ++ int (*disable_plane)(struct drm_plane *plane); ++ void (*destroy)(struct drm_plane *plane); ++}; ++ ++/** ++ * drm_plane - central DRM plane control structure ++ * @dev: DRM device this plane belongs to ++ * @head: for list management ++ * @base: base mode object ++ * @possible_crtcs: pipes this plane can be bound to ++ * @format_types: array of formats supported by this plane ++ * @format_count: number of formats supported ++ * @crtc: currently bound CRTC ++ * @fb: currently bound fb ++ * @gamma_size: size of gamma table ++ * @gamma_store: gamma correction table ++ * @enabled: enabled flag ++ * @funcs: helper functions ++ * @helper_private: storage for drver layer ++ */ ++struct drm_plane { ++ struct drm_device *dev; ++ struct list_head head; ++ ++ struct drm_mode_object base; ++ ++ uint32_t possible_crtcs; ++ uint32_t *format_types; ++ uint32_t format_count; ++ ++ struct drm_crtc *crtc; ++ struct drm_framebuffer *fb; ++ ++ /* CRTC gamma size for reporting to userspace */ ++ uint32_t gamma_size; ++ uint16_t *gamma_store; ++ ++ bool enabled; ++ ++ const struct drm_plane_funcs *funcs; ++ void *helper_private; ++}; ++ ++/** ++ * drm_mode_set - new values for a CRTC config change ++ * @head: list management ++ * @fb: framebuffer to use for new config ++ * @crtc: CRTC whose configuration we're about to change ++ * @mode: mode timings to use ++ * @x: position of this CRTC relative to @fb ++ * @y: position of this CRTC relative to @fb ++ * @connectors: array of connectors to drive with this CRTC if possible ++ * @num_connectors: size of @connectors array ++ * ++ * Represents a single crtc the connectors that it drives with what mode ++ * and from which framebuffer it scans out from. ++ * ++ * This is used to set modes. ++ */ ++struct drm_mode_set { ++ struct list_head head; ++ ++ struct drm_framebuffer *fb; ++ struct drm_crtc *crtc; ++ struct drm_display_mode *mode; ++ ++ uint32_t x; ++ uint32_t y; ++ ++ struct drm_connector **connectors; ++ size_t num_connectors; ++}; ++ ++/** ++ * struct drm_mode_config_funcs - basic driver provided mode setting functions ++ * @fb_create: create a new framebuffer object ++ * @output_poll_changed: function to handle output configuration changes ++ * ++ * Some global (i.e. not per-CRTC, connector, etc) mode setting functions that ++ * involve drivers. ++ */ ++struct drm_mode_config_funcs { ++ struct drm_framebuffer *(*fb_create)(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct drm_mode_fb_cmd2 *mode_cmd); ++ void (*output_poll_changed)(struct drm_device *dev); ++}; ++ ++/** ++ * drm_mode_group - group of mode setting resources for potential sub-grouping ++ * @num_crtcs: CRTC count ++ * @num_encoders: encoder count ++ * @num_connectors: connector count ++ * @id_list: list of KMS object IDs in this group ++ * ++ * Currently this simply tracks the global mode setting state. But in the ++ * future it could allow groups of objects to be set aside into independent ++ * control groups for use by different user level processes (e.g. two X servers ++ * running simultaneously on different heads, each with their own mode ++ * configuration and freedom of mode setting). ++ */ ++struct drm_mode_group { ++ uint32_t num_crtcs; ++ uint32_t num_encoders; ++ uint32_t num_connectors; ++ ++ /* list of object IDs for this group */ ++ uint32_t *id_list; ++}; ++ ++/** ++ * drm_mode_config - Mode configuration control structure ++ * @mutex: mutex protecting KMS related lists and structures ++ * @idr_mutex: mutex for KMS ID allocation and management ++ * @crtc_idr: main KMS ID tracking object ++ * @num_fb: number of fbs available ++ * @fb_list: list of framebuffers available ++ * @num_connector: number of connectors on this device ++ * @connector_list: list of connector objects ++ * @num_encoder: number of encoders on this device ++ * @encoder_list: list of encoder objects ++ * @num_crtc: number of CRTCs on this device ++ * @crtc_list: list of CRTC objects ++ * @min_width: minimum pixel width on this device ++ * @min_height: minimum pixel height on this device ++ * @max_width: maximum pixel width on this device ++ * @max_height: maximum pixel height on this device ++ * @funcs: core driver provided mode setting functions ++ * @fb_base: base address of the framebuffer ++ * @poll_enabled: track polling status for this device ++ * @output_poll_work: delayed work for polling in process context ++ * @*_property: core property tracking ++ * ++ * Core mode resource tracking structure. All CRTC, encoders, and connectors ++ * enumerated by the driver are added here, as are global properties. Some ++ * global restrictions are also here, e.g. dimension restrictions. ++ */ ++struct drm_mode_config { ++ struct mutex mutex; /* protects configuration (mode lists etc.) */ ++ struct mutex idr_mutex; /* for IDR management */ ++ struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */ ++ /* this is limited to one for now */ ++ int num_fb; ++ struct list_head fb_list; ++ int num_connector; ++ struct list_head connector_list; ++ int num_encoder; ++ struct list_head encoder_list; ++ int num_plane; ++ struct list_head plane_list; ++ ++ int num_crtc; ++ struct list_head crtc_list; ++ ++ struct list_head property_list; ++ ++ int min_width, min_height; ++ int max_width, max_height; ++ struct drm_mode_config_funcs *funcs; ++ resource_size_t fb_base; ++ ++ /* output poll support */ ++ bool poll_enabled; ++ struct delayed_work output_poll_work; ++ ++ /* pointers to standard properties */ ++ struct list_head property_blob_list; ++ struct drm_property *edid_property; ++ struct drm_property *dpms_property; ++ ++ /* DVI-I properties */ ++ struct drm_property *dvi_i_subconnector_property; ++ struct drm_property *dvi_i_select_subconnector_property; ++ ++ /* TV properties */ ++ struct drm_property *tv_subconnector_property; ++ struct drm_property *tv_select_subconnector_property; ++ struct drm_property *tv_mode_property; ++ struct drm_property *tv_left_margin_property; ++ struct drm_property *tv_right_margin_property; ++ struct drm_property *tv_top_margin_property; ++ struct drm_property *tv_bottom_margin_property; ++ struct drm_property *tv_brightness_property; ++ struct drm_property *tv_contrast_property; ++ struct drm_property *tv_flicker_reduction_property; ++ struct drm_property *tv_overscan_property; ++ struct drm_property *tv_saturation_property; ++ struct drm_property *tv_hue_property; ++ ++ /* Optional properties */ ++ struct drm_property *scaling_mode_property; ++ struct drm_property *dithering_mode_property; ++ struct drm_property *dirty_info_property; ++ ++ /* dumb ioctl parameters */ ++ uint32_t preferred_depth, prefer_shadow; ++}; ++ ++#define obj_to_crtc(x) container_of(x, struct drm_crtc, base) ++#define obj_to_connector(x) container_of(x, struct drm_connector, base) ++#define obj_to_encoder(x) container_of(x, struct drm_encoder, base) ++#define obj_to_mode(x) container_of(x, struct drm_display_mode, base) ++#define obj_to_fb(x) container_of(x, struct drm_framebuffer, base) ++#define obj_to_property(x) container_of(x, struct drm_property, base) ++#define obj_to_blob(x) container_of(x, struct drm_property_blob, base) ++#define obj_to_plane(x) container_of(x, struct drm_plane, base) ++ ++struct drm_prop_enum_list { ++ int type; ++ char *name; ++}; ++ ++extern int drm_crtc_init(struct drm_device *dev, ++ struct drm_crtc *crtc, ++ const struct drm_crtc_funcs *funcs); ++extern void drm_crtc_cleanup(struct drm_crtc *crtc); ++ ++extern int drm_connector_init(struct drm_device *dev, ++ struct drm_connector *connector, ++ const struct drm_connector_funcs *funcs, ++ int connector_type); ++ ++extern void drm_connector_cleanup(struct drm_connector *connector); ++/* helper to unplug all connectors from sysfs for device */ ++extern void drm_connector_unplug_all(struct drm_device *dev); ++ ++extern int drm_encoder_init(struct drm_device *dev, ++ struct drm_encoder *encoder, ++ const struct drm_encoder_funcs *funcs, ++ int encoder_type); ++ ++extern int drm_plane_init(struct drm_device *dev, ++ struct drm_plane *plane, ++ unsigned long possible_crtcs, ++ const struct drm_plane_funcs *funcs, ++ const uint32_t *formats, uint32_t format_count, ++ bool priv); ++extern void drm_plane_cleanup(struct drm_plane *plane); ++ ++extern void drm_encoder_cleanup(struct drm_encoder *encoder); ++ ++extern char *drm_get_connector_name(struct drm_connector *connector); ++extern char *drm_get_dpms_name(int val); ++extern char *drm_get_dvi_i_subconnector_name(int val); ++extern char *drm_get_dvi_i_select_name(int val); ++extern char *drm_get_tv_subconnector_name(int val); ++extern char *drm_get_tv_select_name(int val); ++extern void drm_fb_release(struct drm_file *file_priv); ++extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); ++extern struct edid *drm_get_edid(struct drm_connector *connector, ++ struct i2c_adapter *adapter); ++extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); ++extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); ++extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); ++extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src); ++extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, ++ const struct drm_display_mode *mode); ++extern void drm_mode_debug_printmodeline(struct drm_display_mode *mode); ++extern void drm_mode_config_init(struct drm_device *dev); ++extern void drm_mode_config_reset(struct drm_device *dev); ++extern void drm_mode_config_cleanup(struct drm_device *dev); ++extern void drm_mode_set_name(struct drm_display_mode *mode); ++extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2); ++extern int drm_mode_width(struct drm_display_mode *mode); ++extern int drm_mode_height(struct drm_display_mode *mode); ++ ++/* for us by fb module */ ++extern int drm_mode_attachmode_crtc(struct drm_device *dev, ++ struct drm_crtc *crtc, ++ const struct drm_display_mode *mode); ++extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode); ++ ++extern struct drm_display_mode *drm_mode_create(struct drm_device *dev); ++extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode); ++extern void drm_mode_list_concat(struct list_head *head, ++ struct list_head *new); ++extern void drm_mode_validate_size(struct drm_device *dev, ++ struct list_head *mode_list, ++ int maxX, int maxY, int maxPitch); ++extern void drm_mode_prune_invalid(struct drm_device *dev, ++ struct list_head *mode_list, bool verbose); ++extern void drm_mode_sort(struct list_head *mode_list); ++extern int drm_mode_hsync(const struct drm_display_mode *mode); ++extern int drm_mode_vrefresh(const struct drm_display_mode *mode); ++extern void drm_mode_set_crtcinfo(struct drm_display_mode *p, ++ int adjust_flags); ++extern void drm_mode_connector_list_update(struct drm_connector *connector); ++extern int drm_mode_connector_update_edid_property(struct drm_connector *connector, ++ struct edid *edid); ++extern int drm_connector_property_set_value(struct drm_connector *connector, ++ struct drm_property *property, ++ uint64_t value); ++extern int drm_connector_property_get_value(struct drm_connector *connector, ++ struct drm_property *property, ++ uint64_t *value); ++extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); ++extern void drm_framebuffer_set_object(struct drm_device *dev, ++ unsigned long handle); ++extern int drm_framebuffer_init(struct drm_device *dev, ++ struct drm_framebuffer *fb, ++ const struct drm_framebuffer_funcs *funcs); ++extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb); ++extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); ++extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); ++extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY); ++extern bool drm_crtc_in_use(struct drm_crtc *crtc); ++ ++extern int drm_connector_attach_property(struct drm_connector *connector, ++ struct drm_property *property, uint64_t init_val); ++extern struct drm_property *drm_property_create(struct drm_device *dev, int flags, ++ const char *name, int num_values); ++extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, ++ const char *name, ++ const struct drm_prop_enum_list *props, ++ int num_values); ++struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, ++ const char *name, ++ uint64_t min, uint64_t max); ++extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); ++extern int drm_property_add_enum(struct drm_property *property, int index, ++ uint64_t value, const char *name); ++extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); ++extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, ++ char *formats[]); ++extern int drm_mode_create_scaling_mode_property(struct drm_device *dev); ++extern int drm_mode_create_dithering_property(struct drm_device *dev); ++extern int drm_mode_create_dirty_info_property(struct drm_device *dev); ++extern char *drm_get_encoder_name(struct drm_encoder *encoder); ++ ++extern int drm_mode_connector_attach_encoder(struct drm_connector *connector, ++ struct drm_encoder *encoder); ++extern void drm_mode_connector_detach_encoder(struct drm_connector *connector, ++ struct drm_encoder *encoder); ++extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc, ++ int gamma_size); ++extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev, ++ uint32_t id, uint32_t type); ++/* IOCTLs */ ++extern int drm_mode_getresources(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getplane_res(struct drm_device *dev, void *data, ++ struct drm_file *file_priv); ++extern int drm_mode_getcrtc(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getconnector(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_setcrtc(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getplane(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_setplane(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_cursor_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_addfb(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_addfb2(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth); ++extern int drm_mode_rmfb(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getfb(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_dirtyfb_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_addmode_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_rmmode_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_attachmode_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_detachmode_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++ ++extern int drm_mode_getproperty_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getblob_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_connector_property_set_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_hotplug_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_replacefb(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_getencoder(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_gamma_get_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_gamma_set_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern u8 *drm_find_cea_extension(struct edid *edid); ++extern bool drm_detect_hdmi_monitor(struct edid *edid); ++extern bool drm_detect_monitor_audio(struct edid *edid); ++extern int drm_mode_page_flip_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, ++ int hdisplay, int vdisplay, int vrefresh, ++ bool reduced, bool interlaced, bool margins); ++extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev, ++ int hdisplay, int vdisplay, int vrefresh, ++ bool interlaced, int margins); ++extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev, ++ int hdisplay, int vdisplay, int vrefresh, ++ bool interlaced, int margins, int GTF_M, ++ int GTF_2C, int GTF_K, int GTF_2J); ++extern int drm_add_modes_noedid(struct drm_connector *connector, ++ int hdisplay, int vdisplay); ++ ++extern int drm_edid_header_is_valid(const u8 *raw_edid); ++extern bool drm_edid_block_valid(u8 *raw_edid); ++extern bool drm_edid_is_valid(struct edid *edid); ++struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev, ++ int hsize, int vsize, int fresh); ++ ++extern int drm_mode_create_dumb_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev, ++ void *data, struct drm_file *file_priv); ++ ++extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth, ++ int *bpp); ++#endif /* __DRM_CRTC_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc_helper.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc_helper.h +new file mode 100644 +index 0000000..37515d1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_crtc_helper.h +@@ -0,0 +1,150 @@ ++/* ++ * Copyright © 2006 Keith Packard ++ * Copyright © 2007-2008 Dave Airlie ++ * Copyright © 2007-2008 Intel Corporation ++ * Jesse Barnes ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++/* ++ * The DRM mode setting helper functions are common code for drivers to use if ++ * they wish. Drivers are not forced to use this code in their ++ * implementations but it would be useful if they code they do use at least ++ * provides a consistent interface and operation to userspace ++ */ ++ ++#ifndef __DRM_CRTC_HELPER_H__ ++#define __DRM_CRTC_HELPER_H__ ++ ++#include ++#include ++#include ++ ++#include ++ ++enum mode_set_atomic { ++ LEAVE_ATOMIC_MODE_SET, ++ ENTER_ATOMIC_MODE_SET, ++}; ++ ++struct drm_crtc_helper_funcs { ++ /* ++ * Control power levels on the CRTC. If the mode passed in is ++ * unsupported, the provider must use the next lowest power level. ++ */ ++ void (*dpms)(struct drm_crtc *crtc, int mode); ++ void (*prepare)(struct drm_crtc *crtc); ++ void (*commit)(struct drm_crtc *crtc); ++ ++ /* Provider can fixup or change mode timings before modeset occurs */ ++ bool (*mode_fixup)(struct drm_crtc *crtc, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode); ++ /* Actually set the mode */ ++ int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode, int x, int y, ++ struct drm_framebuffer *old_fb); ++ ++ /* Move the crtc on the current fb to the given position *optional* */ ++ int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, ++ struct drm_framebuffer *old_fb); ++ int (*mode_set_base_atomic)(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, int x, int y, ++ enum mode_set_atomic); ++ ++ /* reload the current crtc LUT */ ++ void (*load_lut)(struct drm_crtc *crtc); ++ ++ /* disable crtc when not in use - more explicit than dpms off */ ++ void (*disable)(struct drm_crtc *crtc); ++}; ++ ++struct drm_encoder_helper_funcs { ++ void (*dpms)(struct drm_encoder *encoder, int mode); ++ void (*save)(struct drm_encoder *encoder); ++ void (*restore)(struct drm_encoder *encoder); ++ ++ bool (*mode_fixup)(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode); ++ void (*prepare)(struct drm_encoder *encoder); ++ void (*commit)(struct drm_encoder *encoder); ++ void (*mode_set)(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode); ++ struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder); ++ /* detect for DAC style encoders */ ++ enum drm_connector_status (*detect)(struct drm_encoder *encoder, ++ struct drm_connector *connector); ++ /* disable encoder when not in use - more explicit than dpms off */ ++ void (*disable)(struct drm_encoder *encoder); ++}; ++ ++struct drm_connector_helper_funcs { ++ int (*get_modes)(struct drm_connector *connector); ++ int (*mode_valid)(struct drm_connector *connector, ++ struct drm_display_mode *mode); ++ struct drm_encoder *(*best_encoder)(struct drm_connector *connector); ++}; ++ ++extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); ++extern void drm_helper_disable_unused_functions(struct drm_device *dev); ++extern int drm_crtc_helper_set_config(struct drm_mode_set *set); ++extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ++ struct drm_display_mode *mode, ++ int x, int y, ++ struct drm_framebuffer *old_fb); ++extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); ++extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); ++ ++extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode); ++ ++extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, ++ struct drm_mode_fb_cmd2 *mode_cmd); ++ ++static inline void drm_crtc_helper_add(struct drm_crtc *crtc, ++ const struct drm_crtc_helper_funcs *funcs) ++{ ++ crtc->helper_private = (void *)funcs; ++} ++ ++static inline void drm_encoder_helper_add(struct drm_encoder *encoder, ++ const struct drm_encoder_helper_funcs *funcs) ++{ ++ encoder->helper_private = (void *)funcs; ++} ++ ++static inline void drm_connector_helper_add(struct drm_connector *connector, ++ const struct drm_connector_helper_funcs *funcs) ++{ ++ connector->helper_private = (void *)funcs; ++} ++ ++extern int drm_helper_resume_force_mode(struct drm_device *dev); ++extern void drm_kms_helper_poll_init(struct drm_device *dev); ++extern void drm_kms_helper_poll_fini(struct drm_device *dev); ++extern void drm_helper_hpd_irq_event(struct drm_device *dev); ++ ++extern void drm_kms_helper_poll_disable(struct drm_device *dev); ++extern void drm_kms_helper_poll_enable(struct drm_device *dev); ++ ++extern int drm_format_num_planes(uint32_t format); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_dp_helper.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_dp_helper.h +new file mode 100644 +index 0000000..93df2d7 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_dp_helper.h +@@ -0,0 +1,252 @@ ++/* ++ * Copyright © 2008 Keith Packard ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that copyright ++ * notice and this permission notice appear in supporting documentation, and ++ * that the name of the copyright holders not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. The copyright holders make no representations ++ * about the suitability of this software for any purpose. It is provided "as ++ * is" without express or implied warranty. ++ * ++ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO ++ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR ++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE ++ * OF THIS SOFTWARE. ++ */ ++ ++#ifndef _DRM_DP_HELPER_H_ ++#define _DRM_DP_HELPER_H_ ++ ++#include ++#include ++ ++/* From the VESA DisplayPort spec */ ++ ++#define AUX_NATIVE_WRITE 0x8 ++#define AUX_NATIVE_READ 0x9 ++#define AUX_I2C_WRITE 0x0 ++#define AUX_I2C_READ 0x1 ++#define AUX_I2C_STATUS 0x2 ++#define AUX_I2C_MOT 0x4 ++ ++#define AUX_NATIVE_REPLY_ACK (0x0 << 4) ++#define AUX_NATIVE_REPLY_NACK (0x1 << 4) ++#define AUX_NATIVE_REPLY_DEFER (0x2 << 4) ++#define AUX_NATIVE_REPLY_MASK (0x3 << 4) ++ ++#define AUX_I2C_REPLY_ACK (0x0 << 6) ++#define AUX_I2C_REPLY_NACK (0x1 << 6) ++#define AUX_I2C_REPLY_DEFER (0x2 << 6) ++#define AUX_I2C_REPLY_MASK (0x3 << 6) ++ ++/* AUX CH addresses */ ++/* DPCD */ ++#define DP_DPCD_REV 0x000 ++ ++#define DP_MAX_LINK_RATE 0x001 ++ ++#define DP_MAX_LANE_COUNT 0x002 ++# define DP_MAX_LANE_COUNT_MASK 0x1f ++# define DP_TPS3_SUPPORTED (1 << 6) ++# define DP_ENHANCED_FRAME_CAP (1 << 7) ++ ++#define DP_MAX_DOWNSPREAD 0x003 ++# define DP_NO_AUX_HANDSHAKE_LINK_TRAINING (1 << 6) ++ ++#define DP_NORP 0x004 ++ ++#define DP_DOWNSTREAMPORT_PRESENT 0x005 ++# define DP_DWN_STRM_PORT_PRESENT (1 << 0) ++# define DP_DWN_STRM_PORT_TYPE_MASK 0x06 ++/* 00b = DisplayPort */ ++/* 01b = Analog */ ++/* 10b = TMDS or HDMI */ ++/* 11b = Other */ ++# define DP_FORMAT_CONVERSION (1 << 3) ++ ++#define DP_MAIN_LINK_CHANNEL_CODING 0x006 ++ ++#define DP_EDP_CONFIGURATION_CAP 0x00d ++#define DP_TRAINING_AUX_RD_INTERVAL 0x00e ++ ++#define DP_PSR_SUPPORT 0x070 ++# define DP_PSR_IS_SUPPORTED 1 ++#define DP_PSR_CAPS 0x071 ++# define DP_PSR_NO_TRAIN_ON_EXIT 1 ++# define DP_PSR_SETUP_TIME_330 (0 << 1) ++# define DP_PSR_SETUP_TIME_275 (1 << 1) ++# define DP_PSR_SETUP_TIME_220 (2 << 1) ++# define DP_PSR_SETUP_TIME_165 (3 << 1) ++# define DP_PSR_SETUP_TIME_110 (4 << 1) ++# define DP_PSR_SETUP_TIME_55 (5 << 1) ++# define DP_PSR_SETUP_TIME_0 (6 << 1) ++# define DP_PSR_SETUP_TIME_MASK (7 << 1) ++# define DP_PSR_SETUP_TIME_SHIFT 1 ++ ++/* link configuration */ ++#define DP_LINK_BW_SET 0x100 ++# define DP_LINK_BW_1_62 0x06 ++# define DP_LINK_BW_2_7 0x0a ++# define DP_LINK_BW_5_4 0x14 ++ ++#define DP_LANE_COUNT_SET 0x101 ++# define DP_LANE_COUNT_MASK 0x0f ++# define DP_LANE_COUNT_ENHANCED_FRAME_EN (1 << 7) ++ ++#define DP_TRAINING_PATTERN_SET 0x102 ++# define DP_TRAINING_PATTERN_DISABLE 0 ++# define DP_TRAINING_PATTERN_1 1 ++# define DP_TRAINING_PATTERN_2 2 ++# define DP_TRAINING_PATTERN_3 3 ++# define DP_TRAINING_PATTERN_MASK 0x3 ++ ++# define DP_LINK_QUAL_PATTERN_DISABLE (0 << 2) ++# define DP_LINK_QUAL_PATTERN_D10_2 (1 << 2) ++# define DP_LINK_QUAL_PATTERN_ERROR_RATE (2 << 2) ++# define DP_LINK_QUAL_PATTERN_PRBS7 (3 << 2) ++# define DP_LINK_QUAL_PATTERN_MASK (3 << 2) ++ ++# define DP_RECOVERED_CLOCK_OUT_EN (1 << 4) ++# define DP_LINK_SCRAMBLING_DISABLE (1 << 5) ++ ++# define DP_SYMBOL_ERROR_COUNT_BOTH (0 << 6) ++# define DP_SYMBOL_ERROR_COUNT_DISPARITY (1 << 6) ++# define DP_SYMBOL_ERROR_COUNT_SYMBOL (2 << 6) ++# define DP_SYMBOL_ERROR_COUNT_MASK (3 << 6) ++ ++#define DP_TRAINING_LANE0_SET 0x103 ++#define DP_TRAINING_LANE1_SET 0x104 ++#define DP_TRAINING_LANE2_SET 0x105 ++#define DP_TRAINING_LANE3_SET 0x106 ++ ++# define DP_TRAIN_VOLTAGE_SWING_MASK 0x3 ++# define DP_TRAIN_VOLTAGE_SWING_SHIFT 0 ++# define DP_TRAIN_MAX_SWING_REACHED (1 << 2) ++# define DP_TRAIN_VOLTAGE_SWING_400 (0 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_600 (1 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_800 (2 << 0) ++# define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) ++ ++# define DP_TRAIN_PRE_EMPHASIS_MASK (3 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_0 (0 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_3_5 (1 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_6 (2 << 3) ++# define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) ++ ++# define DP_TRAIN_PRE_EMPHASIS_SHIFT 3 ++# define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED (1 << 5) ++ ++#define DP_DOWNSPREAD_CTRL 0x107 ++# define DP_SPREAD_AMP_0_5 (1 << 4) ++ ++#define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 ++# define DP_SET_ANSI_8B10B (1 << 0) ++ ++#define DP_PSR_EN_CFG 0x170 ++# define DP_PSR_ENABLE (1 << 0) ++# define DP_PSR_MAIN_LINK_ACTIVE (1 << 1) ++# define DP_PSR_CRC_VERIFICATION (1 << 2) ++# define DP_PSR_FRAME_CAPTURE (1 << 3) ++ ++#define DP_DEVICE_SERVICE_IRQ_VECTOR 0x201 ++# define DP_REMOTE_CONTROL_COMMAND_PENDING (1 << 0) ++# define DP_AUTOMATED_TEST_REQUEST (1 << 1) ++# define DP_CP_IRQ (1 << 2) ++# define DP_SINK_SPECIFIC_IRQ (1 << 6) ++ ++#define DP_EDP_CONFIGURATION_SET 0x10a ++ ++#define DP_LANE0_1_STATUS 0x202 ++#define DP_LANE2_3_STATUS 0x203 ++# define DP_LANE_CR_DONE (1 << 0) ++# define DP_LANE_CHANNEL_EQ_DONE (1 << 1) ++# define DP_LANE_SYMBOL_LOCKED (1 << 2) ++ ++#define DP_CHANNEL_EQ_BITS (DP_LANE_CR_DONE | \ ++ DP_LANE_CHANNEL_EQ_DONE | \ ++ DP_LANE_SYMBOL_LOCKED) ++ ++#define DP_LANE_ALIGN_STATUS_UPDATED 0x204 ++ ++#define DP_INTERLANE_ALIGN_DONE (1 << 0) ++#define DP_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6) ++#define DP_LINK_STATUS_UPDATED (1 << 7) ++ ++#define DP_SINK_STATUS 0x205 ++ ++#define DP_RECEIVE_PORT_0_STATUS (1 << 0) ++#define DP_RECEIVE_PORT_1_STATUS (1 << 1) ++ ++#define DP_ADJUST_REQUEST_LANE0_1 0x206 ++#define DP_ADJUST_REQUEST_LANE2_3 0x207 ++# define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK 0x03 ++# define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT 0 ++# define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK 0x0c ++# define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT 2 ++# define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK 0x30 ++# define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT 4 ++# define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK 0xc0 ++# define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT 6 ++ ++#define DP_TEST_REQUEST 0x218 ++# define DP_TEST_LINK_TRAINING (1 << 0) ++# define DP_TEST_LINK_PATTERN (1 << 1) ++# define DP_TEST_LINK_EDID_READ (1 << 2) ++# define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ ++ ++#define DP_TEST_LINK_RATE 0x219 ++# define DP_LINK_RATE_162 (0x6) ++# define DP_LINK_RATE_27 (0xa) ++ ++#define DP_TEST_LANE_COUNT 0x220 ++ ++#define DP_TEST_PATTERN 0x221 ++ ++#define DP_TEST_RESPONSE 0x260 ++# define DP_TEST_ACK (1 << 0) ++# define DP_TEST_NAK (1 << 1) ++# define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2) ++ ++#define DP_SET_POWER 0x600 ++# define DP_SET_POWER_D0 0x1 ++# define DP_SET_POWER_D3 0x2 ++ ++#define DP_PSR_ERROR_STATUS 0x2006 ++# define DP_PSR_LINK_CRC_ERROR (1 << 0) ++# define DP_PSR_RFB_STORAGE_ERROR (1 << 1) ++ ++#define DP_PSR_ESI 0x2007 ++# define DP_PSR_CAPS_CHANGE (1 << 0) ++ ++#define DP_PSR_STATUS 0x2008 ++# define DP_PSR_SINK_INACTIVE 0 ++# define DP_PSR_SINK_ACTIVE_SRC_SYNCED 1 ++# define DP_PSR_SINK_ACTIVE_RFB 2 ++# define DP_PSR_SINK_ACTIVE_SINK_SYNCED 3 ++# define DP_PSR_SINK_ACTIVE_RESYNC 4 ++# define DP_PSR_SINK_INTERNAL_ERROR 7 ++# define DP_PSR_SINK_STATE_MASK 0x07 ++ ++#define MODE_I2C_START 1 ++#define MODE_I2C_WRITE 2 ++#define MODE_I2C_READ 4 ++#define MODE_I2C_STOP 8 ++ ++struct i2c_algo_dp_aux_data { ++ bool running; ++ u16 address; ++ int (*aux_ch) (struct i2c_adapter *adapter, ++ int mode, uint8_t write_byte, ++ uint8_t *read_byte); ++}; ++ ++int ++i2c_dp_aux_add_bus(struct i2c_adapter *adapter); ++ ++#endif /* _DRM_DP_HELPER_H_ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_edid.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_edid.h +new file mode 100644 +index 0000000..bcb9a66 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_edid.h +@@ -0,0 +1,243 @@ ++/* ++ * Copyright © 2007-2008 Intel Corporation ++ * Jesse Barnes ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++#ifndef __DRM_EDID_H__ ++#define __DRM_EDID_H__ ++ ++#include ++ ++#define EDID_LENGTH 128 ++#define DDC_ADDR 0x50 ++ ++#define CEA_EXT 0x02 ++#define VTB_EXT 0x10 ++#define DI_EXT 0x40 ++#define LS_EXT 0x50 ++#define MI_EXT 0x60 ++ ++struct est_timings { ++ u8 t1; ++ u8 t2; ++ u8 mfg_rsvd; ++} __attribute__((packed)); ++ ++/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ ++#define EDID_TIMING_ASPECT_SHIFT 6 ++#define EDID_TIMING_ASPECT_MASK (0x3 << EDID_TIMING_ASPECT_SHIFT) ++ ++/* need to add 60 */ ++#define EDID_TIMING_VFREQ_SHIFT 0 ++#define EDID_TIMING_VFREQ_MASK (0x3f << EDID_TIMING_VFREQ_SHIFT) ++ ++struct std_timing { ++ u8 hsize; /* need to multiply by 8 then add 248 */ ++ u8 vfreq_aspect; ++} __attribute__((packed)); ++ ++#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1) ++#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2) ++#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3) ++#define DRM_EDID_PT_STEREO (1 << 5) ++#define DRM_EDID_PT_INTERLACED (1 << 7) ++ ++/* If detailed data is pixel timing */ ++struct detailed_pixel_timing { ++ u8 hactive_lo; ++ u8 hblank_lo; ++ u8 hactive_hblank_hi; ++ u8 vactive_lo; ++ u8 vblank_lo; ++ u8 vactive_vblank_hi; ++ u8 hsync_offset_lo; ++ u8 hsync_pulse_width_lo; ++ u8 vsync_offset_pulse_width_lo; ++ u8 hsync_vsync_offset_pulse_width_hi; ++ u8 width_mm_lo; ++ u8 height_mm_lo; ++ u8 width_height_mm_hi; ++ u8 hborder; ++ u8 vborder; ++ u8 misc; ++} __attribute__((packed)); ++ ++/* If it's not pixel timing, it'll be one of the below */ ++struct detailed_data_string { ++ u8 str[13]; ++} __attribute__((packed)); ++ ++struct detailed_data_monitor_range { ++ u8 min_vfreq; ++ u8 max_vfreq; ++ u8 min_hfreq_khz; ++ u8 max_hfreq_khz; ++ u8 pixel_clock_mhz; /* need to multiply by 10 */ ++ __le16 sec_gtf_toggle; /* A000=use above, 20=use below */ ++ u8 hfreq_start_khz; /* need to multiply by 2 */ ++ u8 c; /* need to divide by 2 */ ++ __le16 m; ++ u8 k; ++ u8 j; /* need to divide by 2 */ ++} __attribute__((packed)); ++ ++struct detailed_data_wpindex { ++ u8 white_yx_lo; /* Lower 2 bits each */ ++ u8 white_x_hi; ++ u8 white_y_hi; ++ u8 gamma; /* need to divide by 100 then add 1 */ ++} __attribute__((packed)); ++ ++struct detailed_data_color_point { ++ u8 windex1; ++ u8 wpindex1[3]; ++ u8 windex2; ++ u8 wpindex2[3]; ++} __attribute__((packed)); ++ ++struct cvt_timing { ++ u8 code[3]; ++} __attribute__((packed)); ++ ++struct detailed_non_pixel { ++ u8 pad1; ++ u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name ++ fb=color point data, fa=standard timing data, ++ f9=undefined, f8=mfg. reserved */ ++ u8 pad2; ++ union { ++ struct detailed_data_string str; ++ struct detailed_data_monitor_range range; ++ struct detailed_data_wpindex color; ++ struct std_timing timings[6]; ++ struct cvt_timing cvt[4]; ++ } data; ++} __attribute__((packed)); ++ ++#define EDID_DETAIL_EST_TIMINGS 0xf7 ++#define EDID_DETAIL_CVT_3BYTE 0xf8 ++#define EDID_DETAIL_COLOR_MGMT_DATA 0xf9 ++#define EDID_DETAIL_STD_MODES 0xfa ++#define EDID_DETAIL_MONITOR_CPDATA 0xfb ++#define EDID_DETAIL_MONITOR_NAME 0xfc ++#define EDID_DETAIL_MONITOR_RANGE 0xfd ++#define EDID_DETAIL_MONITOR_STRING 0xfe ++#define EDID_DETAIL_MONITOR_SERIAL 0xff ++ ++struct detailed_timing { ++ __le16 pixel_clock; /* need to multiply by 10 KHz */ ++ union { ++ struct detailed_pixel_timing pixel_data; ++ struct detailed_non_pixel other_data; ++ } data; ++} __attribute__((packed)); ++ ++#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 0) ++#define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 1) ++#define DRM_EDID_INPUT_COMPOSITE_SYNC (1 << 2) ++#define DRM_EDID_INPUT_SEPARATE_SYNCS (1 << 3) ++#define DRM_EDID_INPUT_BLANK_TO_BLACK (1 << 4) ++#define DRM_EDID_INPUT_VIDEO_LEVEL (3 << 5) ++#define DRM_EDID_INPUT_DIGITAL (1 << 7) ++#define DRM_EDID_DIGITAL_DEPTH_MASK (7 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_UNDEF (0 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_6 (1 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_8 (2 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_10 (3 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_12 (4 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_14 (5 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_16 (6 << 4) ++#define DRM_EDID_DIGITAL_DEPTH_RSVD (7 << 4) ++#define DRM_EDID_DIGITAL_TYPE_UNDEF (0) ++#define DRM_EDID_DIGITAL_TYPE_DVI (1) ++#define DRM_EDID_DIGITAL_TYPE_HDMI_A (2) ++#define DRM_EDID_DIGITAL_TYPE_HDMI_B (3) ++#define DRM_EDID_DIGITAL_TYPE_MDDI (4) ++#define DRM_EDID_DIGITAL_TYPE_DP (5) ++ ++#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 0) ++#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1) ++#define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 2) ++/* If analog */ ++#define DRM_EDID_FEATURE_DISPLAY_TYPE (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ ++/* If digital */ ++#define DRM_EDID_FEATURE_COLOR_MASK (3 << 3) ++#define DRM_EDID_FEATURE_RGB (0 << 3) ++#define DRM_EDID_FEATURE_RGB_YCRCB444 (1 << 3) ++#define DRM_EDID_FEATURE_RGB_YCRCB422 (2 << 3) ++#define DRM_EDID_FEATURE_RGB_YCRCB (3 << 3) /* both 4:4:4 and 4:2:2 */ ++ ++#define DRM_EDID_FEATURE_PM_ACTIVE_OFF (1 << 5) ++#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 6) ++#define DRM_EDID_FEATURE_PM_STANDBY (1 << 7) ++ ++struct edid { ++ u8 header[8]; ++ /* Vendor & product info */ ++ u8 mfg_id[2]; ++ u8 prod_code[2]; ++ u32 serial; /* FIXME: byte order */ ++ u8 mfg_week; ++ u8 mfg_year; ++ /* EDID version */ ++ u8 version; ++ u8 revision; ++ /* Display info: */ ++ u8 input; ++ u8 width_cm; ++ u8 height_cm; ++ u8 gamma; ++ u8 features; ++ /* Color characteristics */ ++ u8 red_green_lo; ++ u8 black_white_lo; ++ u8 red_x; ++ u8 red_y; ++ u8 green_x; ++ u8 green_y; ++ u8 blue_x; ++ u8 blue_y; ++ u8 white_x; ++ u8 white_y; ++ /* Est. timings and mfg rsvd timings*/ ++ struct est_timings established_timings; ++ /* Standard timings 1-8*/ ++ struct std_timing standard_timings[8]; ++ /* Detailing timings 1-4 */ ++ struct detailed_timing detailed_timings[4]; ++ /* Number of 128 byte ext. blocks */ ++ u8 extensions; ++ /* Checksum */ ++ u8 checksum; ++} __attribute__((packed)); ++ ++#define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) ++ ++struct drm_encoder; ++struct drm_connector; ++struct drm_display_mode; ++void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); ++int drm_av_sync_delay(struct drm_connector *connector, ++ struct drm_display_mode *mode); ++struct drm_connector *drm_select_eld(struct drm_encoder *encoder, ++ struct drm_display_mode *mode); ++int drm_load_edid_firmware(struct drm_connector *connector); ++ ++#endif /* __DRM_EDID_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_encoder_slave.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_encoder_slave.h +new file mode 100644 +index 0000000..2f65633 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_encoder_slave.h +@@ -0,0 +1,162 @@ ++/* ++ * Copyright (C) 2009 Francisco Jerez. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining ++ * a copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sublicense, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial ++ * portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE ++ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ++ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ++ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ */ ++ ++#ifndef __DRM_ENCODER_SLAVE_H__ ++#define __DRM_ENCODER_SLAVE_H__ ++ ++#include "drmP.h" ++#include "drm_crtc.h" ++ ++/** ++ * struct drm_encoder_slave_funcs - Entry points exposed by a slave encoder driver ++ * @set_config: Initialize any encoder-specific modesetting parameters. ++ * The meaning of the @params parameter is implementation ++ * dependent. It will usually be a structure with DVO port ++ * data format settings or timings. It's not required for ++ * the new parameters to take effect until the next mode ++ * is set. ++ * ++ * Most of its members are analogous to the function pointers in ++ * &drm_encoder_helper_funcs and they can optionally be used to ++ * initialize the latter. Connector-like methods (e.g. @get_modes and ++ * @set_property) will typically be wrapped around and only be called ++ * if the encoder is the currently selected one for the connector. ++ */ ++struct drm_encoder_slave_funcs { ++ void (*set_config)(struct drm_encoder *encoder, ++ void *params); ++ ++ void (*destroy)(struct drm_encoder *encoder); ++ void (*dpms)(struct drm_encoder *encoder, int mode); ++ void (*save)(struct drm_encoder *encoder); ++ void (*restore)(struct drm_encoder *encoder); ++ bool (*mode_fixup)(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode); ++ int (*mode_valid)(struct drm_encoder *encoder, ++ struct drm_display_mode *mode); ++ void (*mode_set)(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode); ++ ++ enum drm_connector_status (*detect)(struct drm_encoder *encoder, ++ struct drm_connector *connector); ++ int (*get_modes)(struct drm_encoder *encoder, ++ struct drm_connector *connector); ++ int (*create_resources)(struct drm_encoder *encoder, ++ struct drm_connector *connector); ++ int (*set_property)(struct drm_encoder *encoder, ++ struct drm_connector *connector, ++ struct drm_property *property, ++ uint64_t val); ++ ++}; ++ ++/** ++ * struct drm_encoder_slave - Slave encoder struct ++ * @base: DRM encoder object. ++ * @slave_funcs: Slave encoder callbacks. ++ * @slave_priv: Slave encoder private data. ++ * @bus_priv: Bus specific data. ++ * ++ * A &drm_encoder_slave has two sets of callbacks, @slave_funcs and the ++ * ones in @base. The former are never actually called by the common ++ * CRTC code, it's just a convenience for splitting the encoder ++ * functions in an upper, GPU-specific layer and a (hopefully) ++ * GPU-agnostic lower layer: It's the GPU driver responsibility to ++ * call the slave methods when appropriate. ++ * ++ * drm_i2c_encoder_init() provides a way to get an implementation of ++ * this. ++ */ ++struct drm_encoder_slave { ++ struct drm_encoder base; ++ ++ struct drm_encoder_slave_funcs *slave_funcs; ++ void *slave_priv; ++ void *bus_priv; ++}; ++#define to_encoder_slave(x) container_of((x), struct drm_encoder_slave, base) ++ ++int drm_i2c_encoder_init(struct drm_device *dev, ++ struct drm_encoder_slave *encoder, ++ struct i2c_adapter *adap, ++ const struct i2c_board_info *info); ++ ++ ++/** ++ * struct drm_i2c_encoder_driver ++ * ++ * Describes a device driver for an encoder connected to the GPU ++ * through an I2C bus. In addition to the entry points in @i2c_driver ++ * an @encoder_init function should be provided. It will be called to ++ * give the driver an opportunity to allocate any per-encoder data ++ * structures and to initialize the @slave_funcs and (optionally) ++ * @slave_priv members of @encoder. ++ */ ++struct drm_i2c_encoder_driver { ++ struct i2c_driver i2c_driver; ++ ++ int (*encoder_init)(struct i2c_client *client, ++ struct drm_device *dev, ++ struct drm_encoder_slave *encoder); ++ ++}; ++#define to_drm_i2c_encoder_driver(x) container_of((x), \ ++ struct drm_i2c_encoder_driver, \ ++ i2c_driver) ++ ++/** ++ * drm_i2c_encoder_get_client - Get the I2C client corresponding to an encoder ++ */ ++static inline struct i2c_client *drm_i2c_encoder_get_client(struct drm_encoder *encoder) ++{ ++ return (struct i2c_client *)to_encoder_slave(encoder)->bus_priv; ++} ++ ++/** ++ * drm_i2c_encoder_register - Register an I2C encoder driver ++ * @owner: Module containing the driver. ++ * @driver: Driver to be registered. ++ */ ++static inline int drm_i2c_encoder_register(struct module *owner, ++ struct drm_i2c_encoder_driver *driver) ++{ ++ return i2c_register_driver(owner, &driver->i2c_driver); ++} ++ ++/** ++ * drm_i2c_encoder_unregister - Unregister an I2C encoder driver ++ * @driver: Driver to be unregistered. ++ */ ++static inline void drm_i2c_encoder_unregister(struct drm_i2c_encoder_driver *driver) ++{ ++ i2c_del_driver(&driver->i2c_driver); ++} ++ ++void drm_i2c_encoder_destroy(struct drm_encoder *encoder); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fb_helper.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fb_helper.h +new file mode 100644 +index 0000000..5120b01 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fb_helper.h +@@ -0,0 +1,120 @@ ++/* ++ * Copyright (c) 2006-2009 Red Hat Inc. ++ * Copyright (c) 2006-2008 Intel Corporation ++ * Copyright (c) 2007 Dave Airlie ++ * ++ * DRM framebuffer helper functions ++ * ++ * Permission to use, copy, modify, distribute, and sell this software and its ++ * documentation for any purpose is hereby granted without fee, provided that ++ * the above copyright notice appear in all copies and that both that copyright ++ * notice and this permission notice appear in supporting documentation, and ++ * that the name of the copyright holders not be used in advertising or ++ * publicity pertaining to distribution of the software without specific, ++ * written prior permission. The copyright holders make no representations ++ * about the suitability of this software for any purpose. It is provided "as ++ * is" without express or implied warranty. ++ * ++ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO ++ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR ++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, ++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE ++ * OF THIS SOFTWARE. ++ * ++ * Authors: ++ * Dave Airlie ++ * Jesse Barnes ++ */ ++#ifndef DRM_FB_HELPER_H ++#define DRM_FB_HELPER_H ++ ++struct drm_fb_helper; ++ ++#include ++ ++struct drm_fb_helper_crtc { ++ struct drm_mode_set mode_set; ++ struct drm_display_mode *desired_mode; ++}; ++ ++struct drm_fb_helper_surface_size { ++ u32 fb_width; ++ u32 fb_height; ++ u32 surface_width; ++ u32 surface_height; ++ u32 surface_bpp; ++ u32 surface_depth; ++}; ++ ++struct drm_fb_helper_funcs { ++ void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, ++ u16 blue, int regno); ++ void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green, ++ u16 *blue, int regno); ++ ++ int (*fb_probe)(struct drm_fb_helper *helper, ++ struct drm_fb_helper_surface_size *sizes); ++}; ++ ++struct drm_fb_helper_connector { ++ struct drm_connector *connector; ++ struct drm_cmdline_mode cmdline_mode; ++}; ++ ++struct drm_fb_helper { ++ struct drm_framebuffer *fb; ++ struct drm_framebuffer *saved_fb; ++ struct drm_device *dev; ++ struct drm_display_mode *mode; ++ int crtc_count; ++ struct drm_fb_helper_crtc *crtc_info; ++ int connector_count; ++ struct drm_fb_helper_connector **connector_info; ++ struct drm_fb_helper_funcs *funcs; ++ struct fb_info *fbdev; ++ u32 pseudo_palette[17]; ++ struct list_head kernel_fb_list; ++ ++ /* we got a hotplug but fbdev wasn't running the console ++ delay until next set_par */ ++ bool delayed_hotplug; ++}; ++ ++int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, ++ int preferred_bpp); ++ ++int drm_fb_helper_init(struct drm_device *dev, ++ struct drm_fb_helper *helper, int crtc_count, ++ int max_conn); ++void drm_fb_helper_fini(struct drm_fb_helper *helper); ++int drm_fb_helper_blank(int blank, struct fb_info *info); ++int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info); ++int drm_fb_helper_set_par(struct fb_info *info); ++int drm_fb_helper_check_var(struct fb_var_screeninfo *var, ++ struct fb_info *info); ++int drm_fb_helper_setcolreg(unsigned regno, ++ unsigned red, ++ unsigned green, ++ unsigned blue, ++ unsigned transp, ++ struct fb_info *info); ++ ++bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper); ++void drm_fb_helper_restore(void); ++void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper, ++ uint32_t fb_width, uint32_t fb_height); ++void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, ++ uint32_t depth); ++ ++int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); ++ ++int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); ++bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); ++int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); ++int drm_fb_helper_debug_enter(struct fb_info *info); ++int drm_fb_helper_debug_leave(struct fb_info *info); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fixed.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fixed.h +new file mode 100644 +index 0000000..4a08a66 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fixed.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright 2009 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Dave Airlie ++ */ ++#ifndef DRM_FIXED_H ++#define DRM_FIXED_H ++ ++typedef union dfixed { ++ u32 full; ++} fixed20_12; ++ ++ ++#define dfixed_const(A) (u32)(((A) << 12))/* + ((B + 0.000122)*4096)) */ ++#define dfixed_const_half(A) (u32)(((A) << 12) + 2048) ++#define dfixed_const_666(A) (u32)(((A) << 12) + 2731) ++#define dfixed_const_8(A) (u32)(((A) << 12) + 3277) ++#define dfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12) ++#define dfixed_init(A) { .full = dfixed_const((A)) } ++#define dfixed_init_half(A) { .full = dfixed_const_half((A)) } ++#define dfixed_trunc(A) ((A).full >> 12) ++ ++static inline u32 dfixed_floor(fixed20_12 A) ++{ ++ u32 non_frac = dfixed_trunc(A); ++ ++ return dfixed_const(non_frac); ++} ++ ++static inline u32 dfixed_ceil(fixed20_12 A) ++{ ++ u32 non_frac = dfixed_trunc(A); ++ ++ if (A.full > dfixed_const(non_frac)) ++ return dfixed_const(non_frac + 1); ++ else ++ return dfixed_const(non_frac); ++} ++ ++static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) ++{ ++ u64 tmp = ((u64)A.full << 13); ++ ++ do_div(tmp, B.full); ++ tmp += 1; ++ tmp /= 2; ++ return lower_32_bits(tmp); ++} ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fourcc.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fourcc.h +new file mode 100644 +index 0000000..bdf0152 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_fourcc.h +@@ -0,0 +1,137 @@ ++/* ++ * Copyright 2011 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef DRM_FOURCC_H ++#define DRM_FOURCC_H ++ ++#include ++ ++#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ ++ ((__u32)(c) << 16) | ((__u32)(d) << 24)) ++ ++#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ ++ ++/* color index */ ++#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ ++ ++/* 8 bpp RGB */ ++#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ ++#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ ++ ++/* 16 bpp RGB */ ++#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */ ++#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */ ++#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */ ++#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */ ++ ++#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */ ++#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */ ++#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */ ++#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */ ++ ++#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */ ++#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */ ++#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */ ++#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */ ++ ++#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */ ++#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */ ++#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */ ++#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */ ++ ++#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ ++#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */ ++ ++/* 24 bpp RGB */ ++#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */ ++#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */ ++ ++/* 32 bpp RGB */ ++#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ ++#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */ ++#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ ++#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */ ++ ++#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */ ++#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */ ++#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ ++#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ ++ ++#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */ ++#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */ ++#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */ ++#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */ ++ ++#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */ ++#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */ ++#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ ++#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ ++ ++/* packed YCbCr */ ++#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ ++#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ ++#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ ++#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ ++ ++#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ ++ ++/* ++ * 2 plane YCbCr ++ * index 0 = Y plane, [7:0] Y ++ * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian ++ * or ++ * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian ++ */ ++#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ ++#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ ++ ++/* 2 non contiguous plane YCbCr */ ++#define DRM_FORMAT_NV12M fourcc_code('N', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane */ ++#define DRM_FORMAT_NV12MT fourcc_code('T', 'M', '1', '2') /* 2x2 subsampled Cr:Cb plane 64x32 macroblocks */ ++ ++/* ++ * 3 plane YCbCr ++ * index 0: Y plane, [7:0] Y ++ * index 1: Cb plane, [7:0] Cb ++ * index 2: Cr plane, [7:0] Cr ++ * or ++ * index 1: Cr plane, [7:0] Cr ++ * index 2: Cb plane, [7:0] Cb ++ */ ++#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */ ++#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */ ++#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */ ++#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */ ++#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ ++#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ ++#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */ ++#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */ ++#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ ++#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ ++ ++/* 3 non contiguous plane YCbCr */ ++#define DRM_FORMAT_YUV420M fourcc_code('Y', 'M', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ ++ ++#endif /* DRM_FOURCC_H */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_global.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_global.h +new file mode 100644 +index 0000000..a06805e +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_global.h +@@ -0,0 +1,53 @@ ++/************************************************************************** ++ * ++ * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ **************************************************************************/ ++/* ++ * Authors: Thomas Hellstrom ++ */ ++ ++#ifndef _DRM_GLOBAL_H_ ++#define _DRM_GLOBAL_H_ ++enum drm_global_types { ++ DRM_GLOBAL_TTM_MEM = 0, ++ DRM_GLOBAL_TTM_BO, ++ DRM_GLOBAL_TTM_OBJECT, ++ DRM_GLOBAL_NUM ++}; ++ ++struct drm_global_reference { ++ enum drm_global_types global_type; ++ size_t size; ++ void *object; ++ int (*init) (struct drm_global_reference *); ++ void (*release) (struct drm_global_reference *); ++}; ++ ++extern void drm_global_init(void); ++extern void drm_global_release(void); ++extern int drm_global_item_ref(struct drm_global_reference *ref); ++extern void drm_global_item_unref(struct drm_global_reference *ref); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_hashtab.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_hashtab.h +new file mode 100644 +index 0000000..3650d5d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_hashtab.h +@@ -0,0 +1,65 @@ ++/************************************************************************** ++ * ++ * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * ++ **************************************************************************/ ++/* ++ * Simple open hash tab implementation. ++ * ++ * Authors: ++ * Thomas Hellström ++ */ ++ ++#ifndef DRM_HASHTAB_H ++#define DRM_HASHTAB_H ++ ++#include ++ ++#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) ++ ++struct drm_hash_item { ++ struct hlist_node head; ++ unsigned long key; ++}; ++ ++struct drm_open_hash { ++ struct hlist_head *table; ++ u8 order; ++}; ++ ++extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order); ++extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); ++extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, ++ unsigned long seed, int bits, int shift, ++ unsigned long add); ++extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); ++ ++extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); ++extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); ++extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); ++extern void drm_ht_remove(struct drm_open_hash *ht); ++ ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mem_util.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mem_util.h +new file mode 100644 +index 0000000..6bd325f +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mem_util.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright © 2008 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ * ++ * Authors: ++ * Jesse Barnes ++ * ++ */ ++#ifndef _DRM_MEM_UTIL_H_ ++#define _DRM_MEM_UTIL_H_ ++ ++#include ++ ++static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) ++{ ++ if (size != 0 && nmemb > ULONG_MAX / size) ++ return NULL; ++ ++ if (size * nmemb <= PAGE_SIZE) ++ return kcalloc(nmemb, size, GFP_KERNEL); ++ ++ return __vmalloc(size * nmemb, ++ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); ++} ++ ++/* Modeled after cairo's malloc_ab, it's like calloc but without the zeroing. */ ++static __inline__ void *drm_malloc_ab(size_t nmemb, size_t size) ++{ ++ if (size != 0 && nmemb > ULONG_MAX / size) ++ return NULL; ++ ++ if (size * nmemb <= PAGE_SIZE) ++ return kmalloc(nmemb * size, GFP_KERNEL); ++ ++ return __vmalloc(size * nmemb, ++ GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); ++} ++ ++static __inline void drm_free_large(void *ptr) ++{ ++ if (!is_vmalloc_addr(ptr)) ++ return kfree(ptr); ++ ++ vfree(ptr); ++} ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_memory.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_memory.h +new file mode 100644 +index 0000000..15af9b3 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_memory.h +@@ -0,0 +1,59 @@ ++/** ++ * \file drm_memory.h ++ * Memory management wrappers for DRM ++ * ++ * \author Rickard E. (Rik) Faith ++ * \author Gareth Hughes ++ */ ++ ++/* ++ * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com ++ * ++ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. ++ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#include ++#include ++#include "drmP.h" ++ ++/** ++ * Cut down version of drm_memory_debug.h, which used to be called ++ * drm_memory.h. ++ */ ++ ++#if __OS_HAS_AGP ++ ++#ifdef HAVE_PAGE_AGP ++#include ++#else ++# ifdef __powerpc__ ++# define PAGE_AGP __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) ++# else ++# define PAGE_AGP PAGE_KERNEL ++# endif ++#endif ++ ++#else /* __OS_HAS_AGP */ ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mm.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mm.h +new file mode 100644 +index 0000000..564b14a +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mm.h +@@ -0,0 +1,188 @@ ++/************************************************************************** ++ * ++ * Copyright 2006-2008 Tungsten Graphics, Inc., Cedar Park, TX. USA. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * ++ **************************************************************************/ ++/* ++ * Authors: ++ * Thomas Hellstrom ++ */ ++ ++#ifndef _DRM_MM_H_ ++#define _DRM_MM_H_ ++ ++/* ++ * Generic range manager structs ++ */ ++#include ++#ifdef CONFIG_DEBUG_FS ++#include ++#endif ++ ++struct drm_mm_node { ++ struct list_head node_list; ++ struct list_head hole_stack; ++ unsigned hole_follows : 1; ++ unsigned scanned_block : 1; ++ unsigned scanned_prev_free : 1; ++ unsigned scanned_next_free : 1; ++ unsigned scanned_preceeds_hole : 1; ++ unsigned allocated : 1; ++ unsigned long start; ++ unsigned long size; ++ struct drm_mm *mm; ++}; ++ ++struct drm_mm { ++ /* List of all memory nodes that immediately precede a free hole. */ ++ struct list_head hole_stack; ++ /* head_node.node_list is the list of all memory nodes, ordered ++ * according to the (increasing) start address of the memory node. */ ++ struct drm_mm_node head_node; ++ struct list_head unused_nodes; ++ int num_unused; ++ spinlock_t unused_lock; ++ unsigned int scan_check_range : 1; ++ unsigned scan_alignment; ++ unsigned long scan_size; ++ unsigned long scan_hit_start; ++ unsigned scan_hit_size; ++ unsigned scanned_blocks; ++ unsigned long scan_start; ++ unsigned long scan_end; ++ struct drm_mm_node *prev_scanned_node; ++}; ++ ++static inline bool drm_mm_node_allocated(struct drm_mm_node *node) ++{ ++ return node->allocated; ++} ++ ++static inline bool drm_mm_initialized(struct drm_mm *mm) ++{ ++ return mm->hole_stack.next; ++} ++#define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \ ++ &(mm)->head_node.node_list, \ ++ node_list) ++#define drm_mm_for_each_scanned_node_reverse(entry, n, mm) \ ++ for (entry = (mm)->prev_scanned_node, \ ++ next = entry ? list_entry(entry->node_list.next, \ ++ struct drm_mm_node, node_list) : NULL; \ ++ entry != NULL; entry = next, \ ++ next = entry ? list_entry(entry->node_list.next, \ ++ struct drm_mm_node, node_list) : NULL) \ ++/* ++ * Basic range manager support (drm_mm.c) ++ */ ++extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, ++ unsigned long size, ++ unsigned alignment, ++ int atomic); ++extern struct drm_mm_node *drm_mm_get_block_range_generic( ++ struct drm_mm_node *node, ++ unsigned long size, ++ unsigned alignment, ++ unsigned long start, ++ unsigned long end, ++ int atomic); ++static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, ++ unsigned long size, ++ unsigned alignment) ++{ ++ return drm_mm_get_block_generic(parent, size, alignment, 0); ++} ++static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, ++ unsigned long size, ++ unsigned alignment) ++{ ++ return drm_mm_get_block_generic(parent, size, alignment, 1); ++} ++static inline struct drm_mm_node *drm_mm_get_block_range( ++ struct drm_mm_node *parent, ++ unsigned long size, ++ unsigned alignment, ++ unsigned long start, ++ unsigned long end) ++{ ++ return drm_mm_get_block_range_generic(parent, size, alignment, ++ start, end, 0); ++} ++static inline struct drm_mm_node *drm_mm_get_block_atomic_range( ++ struct drm_mm_node *parent, ++ unsigned long size, ++ unsigned alignment, ++ unsigned long start, ++ unsigned long end) ++{ ++ return drm_mm_get_block_range_generic(parent, size, alignment, ++ start, end, 1); ++} ++extern int drm_mm_insert_node(struct drm_mm *mm, struct drm_mm_node *node, ++ unsigned long size, unsigned alignment); ++extern int drm_mm_insert_node_in_range(struct drm_mm *mm, ++ struct drm_mm_node *node, ++ unsigned long size, unsigned alignment, ++ unsigned long start, unsigned long end); ++extern void drm_mm_put_block(struct drm_mm_node *cur); ++extern void drm_mm_remove_node(struct drm_mm_node *node); ++extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new); ++extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, ++ unsigned long size, ++ unsigned alignment, ++ int best_match); ++extern struct drm_mm_node *drm_mm_search_free_in_range( ++ const struct drm_mm *mm, ++ unsigned long size, ++ unsigned alignment, ++ unsigned long start, ++ unsigned long end, ++ int best_match); ++extern int drm_mm_init(struct drm_mm *mm, unsigned long start, ++ unsigned long size); ++extern void drm_mm_takedown(struct drm_mm *mm); ++extern int drm_mm_clean(struct drm_mm *mm); ++extern int drm_mm_pre_get(struct drm_mm *mm); ++ ++static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block) ++{ ++ return block->mm; ++} ++ ++void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, ++ unsigned alignment); ++void drm_mm_init_scan_with_range(struct drm_mm *mm, unsigned long size, ++ unsigned alignment, ++ unsigned long start, ++ unsigned long end); ++int drm_mm_scan_add_block(struct drm_mm_node *node); ++int drm_mm_scan_remove_block(struct drm_mm_node *node); ++ ++extern void drm_mm_debug_table(struct drm_mm *mm, const char *prefix); ++#ifdef CONFIG_DEBUG_FS ++int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm); ++#endif ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mode.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mode.h +new file mode 100644 +index 0000000..9242310 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_mode.h +@@ -0,0 +1,447 @@ ++/* ++ * Copyright (c) 2007 Dave Airlie ++ * Copyright (c) 2007 Jakob Bornecrantz ++ * Copyright (c) 2008 Red Hat Inc. ++ * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA ++ * Copyright (c) 2007-2008 Intel Corporation ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++#ifndef _DRM_MODE_H ++#define _DRM_MODE_H ++ ++#include ++ ++#define DRM_DISPLAY_INFO_LEN 32 ++#define DRM_CONNECTOR_NAME_LEN 32 ++#define DRM_DISPLAY_MODE_LEN 32 ++#define DRM_PROP_NAME_LEN 32 ++ ++#define DRM_MODE_TYPE_BUILTIN (1<<0) ++#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) ++#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) ++#define DRM_MODE_TYPE_PREFERRED (1<<3) ++#define DRM_MODE_TYPE_DEFAULT (1<<4) ++#define DRM_MODE_TYPE_USERDEF (1<<5) ++#define DRM_MODE_TYPE_DRIVER (1<<6) ++ ++/* Video mode flags */ ++/* bit compatible with the xorg definitions. */ ++#define DRM_MODE_FLAG_PHSYNC (1<<0) ++#define DRM_MODE_FLAG_NHSYNC (1<<1) ++#define DRM_MODE_FLAG_PVSYNC (1<<2) ++#define DRM_MODE_FLAG_NVSYNC (1<<3) ++#define DRM_MODE_FLAG_INTERLACE (1<<4) ++#define DRM_MODE_FLAG_DBLSCAN (1<<5) ++#define DRM_MODE_FLAG_CSYNC (1<<6) ++#define DRM_MODE_FLAG_PCSYNC (1<<7) ++#define DRM_MODE_FLAG_NCSYNC (1<<8) ++#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ ++#define DRM_MODE_FLAG_BCAST (1<<10) ++#define DRM_MODE_FLAG_PIXMUX (1<<11) ++#define DRM_MODE_FLAG_DBLCLK (1<<12) ++#define DRM_MODE_FLAG_CLKDIV2 (1<<13) ++ ++/* DPMS flags */ ++/* bit compatible with the xorg definitions. */ ++#define DRM_MODE_DPMS_ON 0 ++#define DRM_MODE_DPMS_STANDBY 1 ++#define DRM_MODE_DPMS_SUSPEND 2 ++#define DRM_MODE_DPMS_OFF 3 ++ ++/* Scaling mode options */ ++#define DRM_MODE_SCALE_NONE 0 /* Unmodified timing (display or ++ software can still scale) */ ++#define DRM_MODE_SCALE_FULLSCREEN 1 /* Full screen, ignore aspect */ ++#define DRM_MODE_SCALE_CENTER 2 /* Centered, no scaling */ ++#define DRM_MODE_SCALE_ASPECT 3 /* Full screen, preserve aspect */ ++ ++/* Dithering mode options */ ++#define DRM_MODE_DITHERING_OFF 0 ++#define DRM_MODE_DITHERING_ON 1 ++#define DRM_MODE_DITHERING_AUTO 2 ++ ++/* Dirty info options */ ++#define DRM_MODE_DIRTY_OFF 0 ++#define DRM_MODE_DIRTY_ON 1 ++#define DRM_MODE_DIRTY_ANNOTATE 2 ++ ++struct drm_mode_modeinfo { ++ __u32 clock; ++ __u16 hdisplay, hsync_start, hsync_end, htotal, hskew; ++ __u16 vdisplay, vsync_start, vsync_end, vtotal, vscan; ++ ++ __u32 vrefresh; ++ ++ __u32 flags; ++ __u32 type; ++ char name[DRM_DISPLAY_MODE_LEN]; ++}; ++ ++struct drm_mode_card_res { ++ __u64 fb_id_ptr; ++ __u64 crtc_id_ptr; ++ __u64 connector_id_ptr; ++ __u64 encoder_id_ptr; ++ __u32 count_fbs; ++ __u32 count_crtcs; ++ __u32 count_connectors; ++ __u32 count_encoders; ++ __u32 min_width, max_width; ++ __u32 min_height, max_height; ++}; ++ ++struct drm_mode_crtc { ++ __u64 set_connectors_ptr; ++ __u32 count_connectors; ++ ++ __u32 crtc_id; /**< Id */ ++ __u32 fb_id; /**< Id of framebuffer */ ++ ++ __u32 x, y; /**< Position on the frameuffer */ ++ ++ __u32 gamma_size; ++ __u32 mode_valid; ++ struct drm_mode_modeinfo mode; ++}; ++ ++#define DRM_MODE_PRESENT_TOP_FIELD (1<<0) ++#define DRM_MODE_PRESENT_BOTTOM_FIELD (1<<1) ++ ++/* Planes blend with or override other bits on the CRTC */ ++struct drm_mode_set_plane { ++ __u32 plane_id; ++ __u32 crtc_id; ++ __u32 fb_id; /* fb object contains surface format type */ ++ __u32 flags; /* see above flags */ ++ ++ /* Signed dest location allows it to be partially off screen */ ++ __s32 crtc_x, crtc_y; ++ __u32 crtc_w, crtc_h; ++ ++ /* Source values are 16.16 fixed point */ ++ __u32 src_x, src_y; ++ __u32 src_h, src_w; ++}; ++ ++struct drm_mode_get_plane { ++ __u32 plane_id; ++ ++ __u32 crtc_id; ++ __u32 fb_id; ++ ++ __u32 possible_crtcs; ++ __u32 gamma_size; ++ ++ __u32 count_format_types; ++ __u64 format_type_ptr; ++}; ++ ++struct drm_mode_get_plane_res { ++ __u64 plane_id_ptr; ++ __u32 count_planes; ++}; ++ ++#define DRM_MODE_ENCODER_NONE 0 ++#define DRM_MODE_ENCODER_DAC 1 ++#define DRM_MODE_ENCODER_TMDS 2 ++#define DRM_MODE_ENCODER_LVDS 3 ++#define DRM_MODE_ENCODER_TVDAC 4 ++#define DRM_MODE_ENCODER_VIRTUAL 5 ++ ++struct drm_mode_get_encoder { ++ __u32 encoder_id; ++ __u32 encoder_type; ++ ++ __u32 crtc_id; /**< Id of crtc */ ++ ++ __u32 possible_crtcs; ++ __u32 possible_clones; ++}; ++ ++/* This is for connectors with multiple signal types. */ ++/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ ++#define DRM_MODE_SUBCONNECTOR_Automatic 0 ++#define DRM_MODE_SUBCONNECTOR_Unknown 0 ++#define DRM_MODE_SUBCONNECTOR_DVID 3 ++#define DRM_MODE_SUBCONNECTOR_DVIA 4 ++#define DRM_MODE_SUBCONNECTOR_Composite 5 ++#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 ++#define DRM_MODE_SUBCONNECTOR_Component 8 ++#define DRM_MODE_SUBCONNECTOR_SCART 9 ++ ++#define DRM_MODE_CONNECTOR_Unknown 0 ++#define DRM_MODE_CONNECTOR_VGA 1 ++#define DRM_MODE_CONNECTOR_DVII 2 ++#define DRM_MODE_CONNECTOR_DVID 3 ++#define DRM_MODE_CONNECTOR_DVIA 4 ++#define DRM_MODE_CONNECTOR_Composite 5 ++#define DRM_MODE_CONNECTOR_SVIDEO 6 ++#define DRM_MODE_CONNECTOR_LVDS 7 ++#define DRM_MODE_CONNECTOR_Component 8 ++#define DRM_MODE_CONNECTOR_9PinDIN 9 ++#define DRM_MODE_CONNECTOR_DisplayPort 10 ++#define DRM_MODE_CONNECTOR_HDMIA 11 ++#define DRM_MODE_CONNECTOR_HDMIB 12 ++#define DRM_MODE_CONNECTOR_TV 13 ++#define DRM_MODE_CONNECTOR_eDP 14 ++#define DRM_MODE_CONNECTOR_VIRTUAL 15 ++ ++struct drm_mode_get_connector { ++ ++ __u64 encoders_ptr; ++ __u64 modes_ptr; ++ __u64 props_ptr; ++ __u64 prop_values_ptr; ++ ++ __u32 count_modes; ++ __u32 count_props; ++ __u32 count_encoders; ++ ++ __u32 encoder_id; /**< Current Encoder */ ++ __u32 connector_id; /**< Id */ ++ __u32 connector_type; ++ __u32 connector_type_id; ++ ++ __u32 connection; ++ __u32 mm_width, mm_height; /**< HxW in millimeters */ ++ __u32 subpixel; ++}; ++ ++#define DRM_MODE_PROP_PENDING (1<<0) ++#define DRM_MODE_PROP_RANGE (1<<1) ++#define DRM_MODE_PROP_IMMUTABLE (1<<2) ++#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ ++#define DRM_MODE_PROP_BLOB (1<<4) ++ ++struct drm_mode_property_enum { ++ __u64 value; ++ char name[DRM_PROP_NAME_LEN]; ++}; ++ ++struct drm_mode_get_property { ++ __u64 values_ptr; /* values and blob lengths */ ++ __u64 enum_blob_ptr; /* enum and blob id ptrs */ ++ ++ __u32 prop_id; ++ __u32 flags; ++ char name[DRM_PROP_NAME_LEN]; ++ ++ __u32 count_values; ++ __u32 count_enum_blobs; ++}; ++ ++struct drm_mode_connector_set_property { ++ __u64 value; ++ __u32 prop_id; ++ __u32 connector_id; ++}; ++ ++struct drm_mode_get_blob { ++ __u32 blob_id; ++ __u32 length; ++ __u64 data; ++}; ++ ++struct drm_mode_fb_cmd { ++ __u32 fb_id; ++ __u32 width, height; ++ __u32 pitch; ++ __u32 bpp; ++ __u32 depth; ++ /* driver specific handle */ ++ __u32 handle; ++}; ++ ++#define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ ++ ++struct drm_mode_fb_cmd2 { ++ __u32 fb_id; ++ __u32 width, height; ++ __u32 pixel_format; /* fourcc code from drm_fourcc.h */ ++ __u32 flags; /* see above flags */ ++ ++ /* ++ * In case of planar formats, this ioctl allows up to 4 ++ * buffer objects with offets and pitches per plane. ++ * The pitch and offset order is dictated by the fourcc, ++ * e.g. NV12 (http://fourcc.org/yuv.php#NV12) is described as: ++ * ++ * YUV 4:2:0 image with a plane of 8 bit Y samples ++ * followed by an interleaved U/V plane containing ++ * 8 bit 2x2 subsampled colour difference samples. ++ * ++ * So it would consist of Y as offset[0] and UV as ++ * offeset[1]. Note that offset[0] will generally ++ * be 0. ++ */ ++ __u32 handles[4]; ++ __u32 pitches[4]; /* pitch for each plane */ ++ __u32 offsets[4]; /* offset of each plane */ ++}; ++ ++#define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 ++#define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02 ++#define DRM_MODE_FB_DIRTY_FLAGS 0x03 ++ ++#define DRM_MODE_FB_DIRTY_MAX_CLIPS 256 ++ ++/* ++ * Mark a region of a framebuffer as dirty. ++ * ++ * Some hardware does not automatically update display contents ++ * as a hardware or software draw to a framebuffer. This ioctl ++ * allows userspace to tell the kernel and the hardware what ++ * regions of the framebuffer have changed. ++ * ++ * The kernel or hardware is free to update more then just the ++ * region specified by the clip rects. The kernel or hardware ++ * may also delay and/or coalesce several calls to dirty into a ++ * single update. ++ * ++ * Userspace may annotate the updates, the annotates are a ++ * promise made by the caller that the change is either a copy ++ * of pixels or a fill of a single color in the region specified. ++ * ++ * If the DRM_MODE_FB_DIRTY_ANNOTATE_COPY flag is given then ++ * the number of updated regions are half of num_clips given, ++ * where the clip rects are paired in src and dst. The width and ++ * height of each one of the pairs must match. ++ * ++ * If the DRM_MODE_FB_DIRTY_ANNOTATE_FILL flag is given the caller ++ * promises that the region specified of the clip rects is filled ++ * completely with a single color as given in the color argument. ++ */ ++ ++struct drm_mode_fb_dirty_cmd { ++ __u32 fb_id; ++ __u32 flags; ++ __u32 color; ++ __u32 num_clips; ++ __u64 clips_ptr; ++}; ++ ++struct drm_mode_mode_cmd { ++ __u32 connector_id; ++ struct drm_mode_modeinfo mode; ++}; ++ ++#define DRM_MODE_CURSOR_BO 0x01 ++#define DRM_MODE_CURSOR_MOVE 0x02 ++#define DRM_MODE_CURSOR_FLAGS 0x03 ++ ++/* ++ * depending on the value in flags different members are used. ++ * ++ * CURSOR_BO uses ++ * crtc ++ * width ++ * height ++ * handle - if 0 turns the cursor of ++ * ++ * CURSOR_MOVE uses ++ * crtc ++ * x ++ * y ++ */ ++struct drm_mode_cursor { ++ __u32 flags; ++ __u32 crtc_id; ++ __s32 x; ++ __s32 y; ++ __u32 width; ++ __u32 height; ++ /* driver specific handle */ ++ __u32 handle; ++}; ++ ++struct drm_mode_crtc_lut { ++ __u32 crtc_id; ++ __u32 gamma_size; ++ ++ /* pointers to arrays */ ++ __u64 red; ++ __u64 green; ++ __u64 blue; ++}; ++ ++#define DRM_MODE_PAGE_FLIP_EVENT 0x01 ++#define DRM_MODE_PAGE_FLIP_FLAGS DRM_MODE_PAGE_FLIP_EVENT ++ ++/* ++ * Request a page flip on the specified crtc. ++ * ++ * This ioctl will ask KMS to schedule a page flip for the specified ++ * crtc. Once any pending rendering targeting the specified fb (as of ++ * ioctl time) has completed, the crtc will be reprogrammed to display ++ * that fb after the next vertical refresh. The ioctl returns ++ * immediately, but subsequent rendering to the current fb will block ++ * in the execbuffer ioctl until the page flip happens. If a page ++ * flip is already pending as the ioctl is called, EBUSY will be ++ * returned. ++ * ++ * The ioctl supports one flag, DRM_MODE_PAGE_FLIP_EVENT, which will ++ * request that drm sends back a vblank event (see drm.h: struct ++ * drm_event_vblank) when the page flip is done. The user_data field ++ * passed in with this ioctl will be returned as the user_data field ++ * in the vblank event struct. ++ * ++ * The reserved field must be zero until we figure out something ++ * clever to use it for. ++ */ ++ ++struct drm_mode_crtc_page_flip { ++ __u32 crtc_id; ++ __u32 fb_id; ++ __u32 flags; ++ __u32 reserved; ++ __u64 user_data; ++}; ++ ++/* create a dumb scanout buffer */ ++struct drm_mode_create_dumb { ++ uint32_t height; ++ uint32_t width; ++ uint32_t bpp; ++ uint32_t flags; ++ /* handle, pitch, size will be returned */ ++ uint32_t handle; ++ uint32_t pitch; ++ uint64_t size; ++}; ++ ++/* set up for mmap of a dumb scanout buffer */ ++struct drm_mode_map_dumb { ++ /** Handle for the object being mapped. */ ++ __u32 handle; ++ __u32 pad; ++ /** ++ * Fake offset to use for subsequent mmap call ++ * ++ * This is a fixed-size type for 32/64 compatibility. ++ */ ++ __u64 offset; ++}; ++ ++struct drm_mode_destroy_dumb { ++ uint32_t handle; ++}; ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_os_linux.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_os_linux.h +new file mode 100644 +index 0000000..3933691 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_os_linux.h +@@ -0,0 +1,127 @@ ++/** ++ * \file drm_os_linux.h ++ * OS abstraction macros. ++ */ ++ ++#include /* For task queue support */ ++#include ++ ++#ifndef readq ++static inline u64 readq(void __iomem *reg) ++{ ++ return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32); ++} ++ ++static inline void writeq(u64 val, void __iomem *reg) ++{ ++ writel(val & 0xffffffff, reg); ++ writel(val >> 32, reg + 0x4UL); ++} ++#endif ++ ++/** Current process ID */ ++#define DRM_CURRENTPID task_pid_nr(current) ++#define DRM_SUSER(p) capable(CAP_SYS_ADMIN) ++#define DRM_UDELAY(d) udelay(d) ++/** Read a byte from a MMIO region */ ++#define DRM_READ8(map, offset) readb(((void __iomem *)(map)->handle) + (offset)) ++/** Read a word from a MMIO region */ ++#define DRM_READ16(map, offset) readw(((void __iomem *)(map)->handle) + (offset)) ++/** Read a dword from a MMIO region */ ++#define DRM_READ32(map, offset) readl(((void __iomem *)(map)->handle) + (offset)) ++/** Write a byte into a MMIO region */ ++#define DRM_WRITE8(map, offset, val) writeb(val, ((void __iomem *)(map)->handle) + (offset)) ++/** Write a word into a MMIO region */ ++#define DRM_WRITE16(map, offset, val) writew(val, ((void __iomem *)(map)->handle) + (offset)) ++/** Write a dword into a MMIO region */ ++#define DRM_WRITE32(map, offset, val) writel(val, ((void __iomem *)(map)->handle) + (offset)) ++/** Read memory barrier */ ++ ++/** Read a qword from a MMIO region - be careful using these unless you really understand them */ ++#define DRM_READ64(map, offset) readq(((void __iomem *)(map)->handle) + (offset)) ++/** Write a qword into a MMIO region */ ++#define DRM_WRITE64(map, offset, val) writeq(val, ((void __iomem *)(map)->handle) + (offset)) ++ ++#define DRM_READMEMORYBARRIER() rmb() ++/** Write memory barrier */ ++#define DRM_WRITEMEMORYBARRIER() wmb() ++/** Read/write memory barrier */ ++#define DRM_MEMORYBARRIER() mb() ++ ++/** IRQ handler arguments and return type and values */ ++#define DRM_IRQ_ARGS int irq, void *arg ++ ++/** AGP types */ ++#if __OS_HAS_AGP ++#define DRM_AGP_MEM struct agp_memory ++#define DRM_AGP_KERN struct agp_kern_info ++#else ++/* define some dummy types for non AGP supporting kernels */ ++struct no_agp_kern { ++ unsigned long aper_base; ++ unsigned long aper_size; ++}; ++#define DRM_AGP_MEM int ++#define DRM_AGP_KERN struct no_agp_kern ++#endif ++ ++#if !(__OS_HAS_MTRR) ++static __inline__ int mtrr_add(unsigned long base, unsigned long size, ++ unsigned int type, char increment) ++{ ++ return -ENODEV; ++} ++ ++static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size) ++{ ++ return -ENODEV; ++} ++ ++#define MTRR_TYPE_WRCOMB 1 ++ ++#endif ++ ++/** Other copying of data to kernel space */ ++#define DRM_COPY_FROM_USER(arg1, arg2, arg3) \ ++ copy_from_user(arg1, arg2, arg3) ++/** Other copying of data from kernel space */ ++#define DRM_COPY_TO_USER(arg1, arg2, arg3) \ ++ copy_to_user(arg1, arg2, arg3) ++/* Macros for copyfrom user, but checking readability only once */ ++#define DRM_VERIFYAREA_READ( uaddr, size ) \ ++ (access_ok( VERIFY_READ, uaddr, size ) ? 0 : -EFAULT) ++#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ ++ __copy_from_user(arg1, arg2, arg3) ++#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ ++ __copy_to_user(arg1, arg2, arg3) ++#define DRM_GET_USER_UNCHECKED(val, uaddr) \ ++ __get_user(val, uaddr) ++ ++#define DRM_HZ HZ ++ ++#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ ++do { \ ++ DECLARE_WAITQUEUE(entry, current); \ ++ unsigned long end = jiffies + (timeout); \ ++ add_wait_queue(&(queue), &entry); \ ++ \ ++ for (;;) { \ ++ __set_current_state(TASK_INTERRUPTIBLE); \ ++ if (condition) \ ++ break; \ ++ if (time_after_eq(jiffies, end)) { \ ++ ret = -EBUSY; \ ++ break; \ ++ } \ ++ schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ ++ if (signal_pending(current)) { \ ++ ret = -EINTR; \ ++ break; \ ++ } \ ++ } \ ++ __set_current_state(TASK_RUNNING); \ ++ remove_wait_queue(&(queue), &entry); \ ++} while (0) ++ ++#define DRM_WAKEUP( queue ) wake_up( queue ) ++#define DRM_INIT_WAITQUEUE( queue ) init_waitqueue_head( queue ) +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_pciids.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_pciids.h +new file mode 100644 +index 0000000..d9928c1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_pciids.h +@@ -0,0 +1,784 @@ ++/* ++ This file is auto-generated from the drm_pciids.txt in the DRM CVS ++ Please contact dri-devel@lists.sf.net to add new cards to this list ++*/ ++#define radeon_PCI_IDS \ ++ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \ ++ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ ++ {0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x414A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x414B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \ ++ {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \ ++ {0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ ++ {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ ++ {0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \ ++ {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4B48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4E47, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ ++ {0x1002, 0x4E48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \ ++ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ ++ {0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ ++ {0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \ ++ {0x1002, 0x5157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ ++ {0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \ ++ {0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ ++ {0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ ++ {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5657, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ ++ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS480|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ ++ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ ++ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ ++ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ ++ {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ ++ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \ ++ {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ ++ {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R423|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6703, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6704, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6705, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6706, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6707, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6708, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6709, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6718, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6719, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x671c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x671d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x671f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAYMAN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6721, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6722, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6723, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6724, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6725, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6726, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6728, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6729, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6738, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6739, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x673e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BARTS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6740, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6741, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6743, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6745, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6746, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6747, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x674A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x675B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x675D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6762, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6763, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6764, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6765, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6766, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6771, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6784, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6788, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x678A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6790, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6791, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6792, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6821, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6823, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6824, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6826, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6827, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6829, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x682B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x682D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x682F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6830, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6831, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6837, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6838, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6839, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x683B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x683D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x683F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x684C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x688A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x688C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x688D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6898, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x6899, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x689b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x689c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x689d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_HEMLOCK|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x689e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68a0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68a8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68a9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68ba, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68be, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68bf, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_JUNIPER|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68c7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68c8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68c9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68d9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_REDWOOD|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68e9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68f1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x710A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x710B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x710C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x710E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x710F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7140, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7141, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7142, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7143, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x714F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7153, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x715E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x715F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7183, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7186, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7187, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7188, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x718A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x718B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x718C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x718D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x718F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7193, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x719B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x719F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71D2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71D5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7248, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x724F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7280, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7283, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7284, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x728B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x728C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV570|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7291, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7293, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7297, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV560|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x793f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7941, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x7942, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS600|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x796c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x796d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x796e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x796f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS740|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ ++ {0x1002, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9402, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9403, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9405, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94A3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94B9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9442, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9444, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x944A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x944B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x944C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x944E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x945E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x947B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9487, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9488, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9489, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x948A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x948F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9490, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9491, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9495, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9498, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x949C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x949E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x949F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV730|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x94CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV610|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9504, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9505, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9506, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9507, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9508, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9509, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x950F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9515, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9517, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV670|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9540, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9541, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9542, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x954E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x954F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9553, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9555, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9557, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x955f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV710|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9580, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9581, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9583, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9586, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9587, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9588, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9589, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x958F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV630|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9590, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9593, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9595, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9596, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9597, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9598, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9599, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x959B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV635|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95CD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95CE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x95CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV620|RADEON_NEW_MEMMAP}, \ ++ {0x1002, 0x9610, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9611, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9612, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9613, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9614, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9615, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9616, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS780|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9642, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO2|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ ++ {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ ++ {0x1002, 0x9649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ ++ {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ ++ {0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ ++ {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9804, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x980A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9901, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9903, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9904, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9905, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9906, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9907, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9908, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9909, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x990F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9910, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9913, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9917, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9919, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9990, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9991, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9993, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9994, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9996, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9998, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x9999, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x999A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x999B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x99A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x99A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0x1002, 0x99A4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_ARUBA|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ ++ {0, 0, 0} ++ ++#define r128_PCI_IDS \ ++ {0x1002, 0x4c45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4d46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5041, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5044, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5045, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5046, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5047, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5048, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5049, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x504F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5051, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5052, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5054, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5055, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5245, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5247, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x524b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x524c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x534d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x544C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x5452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define mga_PCI_IDS \ ++ {0x102b, 0x0520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \ ++ {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \ ++ {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G400}, \ ++ {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \ ++ {0, 0, 0} ++ ++#define mach64_PCI_IDS \ ++ {0x1002, 0x4749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4742, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4744, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4752, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4753, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x474e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1002, 0x4c4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define sisdrv_PCI_IDS \ ++ {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ ++ {0x1039, 0x6351, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x18CA, 0x0040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ ++ {0x18CA, 0x0042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ ++ {0, 0, 0} ++ ++#define tdfx_PCI_IDS \ ++ {0x121a, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x121a, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x121a, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x121a, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x121a, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x121a, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define viadrv_PCI_IDS \ ++ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ ++ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ ++ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ ++ {0, 0, 0} ++ ++#define i810_PCI_IDS \ ++ {0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x7125, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x1132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define i830_PCI_IDS \ ++ {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0x8086, 0x358e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define gamma_PCI_IDS \ ++ {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ ++ {0, 0, 0} ++ ++#define savage_PCI_IDS \ ++ {0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \ ++ {0x5333, 0x8a21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \ ++ {0x5333, 0x8a22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \ ++ {0x5333, 0x8a23, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE4}, \ ++ {0x5333, 0x8c10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \ ++ {0x5333, 0x8c11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \ ++ {0x5333, 0x8c12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \ ++ {0x5333, 0x8c13, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE_MX}, \ ++ {0x5333, 0x8c22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c24, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8c2f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SUPERSAVAGE}, \ ++ {0x5333, 0x8a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \ ++ {0x5333, 0x8a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGE}, \ ++ {0x5333, 0x8d01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \ ++ {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \ ++ {0x5333, 0x8d03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \ ++ {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \ ++ {0, 0, 0} ++ ++#define ffb_PCI_IDS \ ++ {0, 0, 0} ++ ++#define i915_PCI_IDS \ ++ {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x258a, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x27ae, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x29b2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x29c2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x29d2, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2a12, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2a42, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2e02, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2e12, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2e22, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2e32, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x2e42, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0xa001, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0xa011, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x35e8, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x0042, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x0046, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0x8086, 0x0102, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, 0xffff00, 0}, \ ++ {0, 0, 0} +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sarea.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sarea.h +new file mode 100644 +index 0000000..ee5389d +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sarea.h +@@ -0,0 +1,84 @@ ++/** ++ * \file drm_sarea.h ++ * \brief SAREA definitions ++ * ++ * \author Michel Dänzer ++ */ ++ ++/* ++ * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the next ++ * paragraph) shall be included in all copies or substantial portions of the ++ * Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ */ ++ ++#ifndef _DRM_SAREA_H_ ++#define _DRM_SAREA_H_ ++ ++#include "drm.h" ++ ++/* SAREA area needs to be at least a page */ ++#if defined(__alpha__) ++#define SAREA_MAX 0x2000U ++#elif defined(__ia64__) ++#define SAREA_MAX 0x10000U /* 64kB */ ++#else ++/* Intel 830M driver needs at least 8k SAREA */ ++#define SAREA_MAX 0x2000U ++#endif ++ ++/** Maximum number of drawables in the SAREA */ ++#define SAREA_MAX_DRAWABLES 256 ++ ++#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000 ++ ++/** SAREA drawable */ ++struct drm_sarea_drawable { ++ unsigned int stamp; ++ unsigned int flags; ++}; ++ ++/** SAREA frame */ ++struct drm_sarea_frame { ++ unsigned int x; ++ unsigned int y; ++ unsigned int width; ++ unsigned int height; ++ unsigned int fullscreen; ++}; ++ ++/** SAREA */ ++struct drm_sarea { ++ /** first thing is always the DRM locking structure */ ++ struct drm_hw_lock lock; ++ /** \todo Use readers/writer lock for drm_sarea::drawable_lock */ ++ struct drm_hw_lock drawable_lock; ++ struct drm_sarea_drawable drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */ ++ struct drm_sarea_frame frame; /**< frame */ ++ drm_context_t dummy_context; ++}; ++ ++#ifndef __KERNEL__ ++typedef struct drm_sarea_drawable drm_sarea_drawable_t; ++typedef struct drm_sarea_frame drm_sarea_frame_t; ++typedef struct drm_sarea drm_sarea_t; ++#endif ++ ++#endif /* _DRM_SAREA_H_ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sman.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sman.h +new file mode 100644 +index 0000000..08ecf83 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sman.h +@@ -0,0 +1,176 @@ ++/************************************************************************** ++ * ++ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA. ++ * All Rights Reserved. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the ++ * "Software"), to deal in the Software without restriction, including ++ * without limitation the rights to use, copy, modify, merge, publish, ++ * distribute, sub license, and/or sell copies of the Software, and to ++ * permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice (including the ++ * next paragraph) shall be included in all copies or substantial portions ++ * of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, ++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ++ * USE OR OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * ++ **************************************************************************/ ++/* ++ * Simple memory MANager interface that keeps track on allocate regions on a ++ * per "owner" basis. All regions associated with an "owner" can be released ++ * with a simple call. Typically if the "owner" exists. The owner is any ++ * "unsigned long" identifier. Can typically be a pointer to a file private ++ * struct or a context identifier. ++ * ++ * Authors: ++ * Thomas Hellström ++ */ ++ ++#ifndef DRM_SMAN_H ++#define DRM_SMAN_H ++ ++#include "drmP.h" ++#include "drm_hashtab.h" ++ ++/* ++ * A class that is an abstration of a simple memory allocator. ++ * The sman implementation provides a default such allocator ++ * using the drm_mm.c implementation. But the user can replace it. ++ * See the SiS implementation, which may use the SiS FB kernel module ++ * for memory management. ++ */ ++ ++struct drm_sman_mm { ++ /* private info. If allocated, needs to be destroyed by the destroy ++ function */ ++ void *private; ++ ++ /* Allocate a memory block with given size and alignment. ++ Return an opaque reference to the memory block */ ++ ++ void *(*allocate) (void *private, unsigned long size, ++ unsigned alignment); ++ ++ /* Free a memory block. "ref" is the opaque reference that we got from ++ the "alloc" function */ ++ ++ void (*free) (void *private, void *ref); ++ ++ /* Free all resources associated with this allocator */ ++ ++ void (*destroy) (void *private); ++ ++ /* Return a memory offset from the opaque reference returned from the ++ "alloc" function */ ++ ++ unsigned long (*offset) (void *private, void *ref); ++}; ++ ++struct drm_memblock_item { ++ struct list_head owner_list; ++ struct drm_hash_item user_hash; ++ void *mm_info; ++ struct drm_sman_mm *mm; ++ struct drm_sman *sman; ++}; ++ ++struct drm_sman { ++ struct drm_sman_mm *mm; ++ int num_managers; ++ struct drm_open_hash owner_hash_tab; ++ struct drm_open_hash user_hash_tab; ++ struct list_head owner_items; ++}; ++ ++/* ++ * Take down a memory manager. This function should only be called after a ++ * successful init and after a call to drm_sman_cleanup. ++ */ ++ ++extern void drm_sman_takedown(struct drm_sman * sman); ++ ++/* ++ * Allocate structures for a manager. ++ * num_managers are the number of memory pools to manage. (VRAM, AGP, ....) ++ * user_order is the log2 of the number of buckets in the user hash table. ++ * set this to approximately log2 of the max number of memory regions ++ * that will be allocated for _all_ pools together. ++ * owner_order is the log2 of the number of buckets in the owner hash table. ++ * set this to approximately log2 of ++ * the number of client file connections that will ++ * be using the manager. ++ * ++ */ ++ ++extern int drm_sman_init(struct drm_sman * sman, unsigned int num_managers, ++ unsigned int user_order, unsigned int owner_order); ++ ++/* ++ * Initialize a drm_mm.c allocator. Should be called only once for each ++ * manager unless a customized allogator is used. ++ */ ++ ++extern int drm_sman_set_range(struct drm_sman * sman, unsigned int manager, ++ unsigned long start, unsigned long size); ++ ++/* ++ * Initialize a customized allocator for one of the managers. ++ * (See the SiS module). The object pointed to by "allocator" is copied, ++ * so it can be destroyed after this call. ++ */ ++ ++extern int drm_sman_set_manager(struct drm_sman * sman, unsigned int mananger, ++ struct drm_sman_mm * allocator); ++ ++/* ++ * Allocate a memory block. Aligment is not implemented yet. ++ */ ++ ++extern struct drm_memblock_item *drm_sman_alloc(struct drm_sman * sman, ++ unsigned int manager, ++ unsigned long size, ++ unsigned alignment, ++ unsigned long owner); ++/* ++ * Free a memory block identified by its user hash key. ++ */ ++ ++extern int drm_sman_free_key(struct drm_sman * sman, unsigned int key); ++ ++/* ++ * returns 1 iff there are no stale memory blocks associated with this owner. ++ * Typically called to determine if we need to idle the hardware and call ++ * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all ++ * resources associated with owner. ++ */ ++ ++extern int drm_sman_owner_clean(struct drm_sman * sman, unsigned long owner); ++ ++/* ++ * Frees all stale memory blocks associated with this owner. Note that this ++ * requires that the hardware is finished with all blocks, so the graphics engine ++ * should be idled before this call is made. This function also frees ++ * any resources associated with "owner" and should be called when owner ++ * is not going to be referenced anymore. ++ */ ++ ++extern void drm_sman_owner_cleanup(struct drm_sman * sman, unsigned long owner); ++ ++/* ++ * Frees all stale memory blocks associated with the memory manager. ++ * See idling above. ++ */ ++ ++extern void drm_sman_cleanup(struct drm_sman * sman); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sysfs.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sysfs.h +new file mode 100644 +index 0000000..1d8e033 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_sysfs.h +@@ -0,0 +1,12 @@ ++#ifndef _DRM_SYSFS_H_ ++#define _DRM_SYSFS_H_ ++ ++/** ++ * This minimalistic include file is intended for users (read TTM) that ++ * don't want to include the full drmP.h file. ++ */ ++ ++extern int drm_class_device_register(struct device *dev); ++extern void drm_class_device_unregister(struct device *dev); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_usb.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_usb.h +new file mode 100644 +index 0000000..33506c1 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/drm_usb.h +@@ -0,0 +1,15 @@ ++#ifndef DRM_USB_H ++#define DRM_USB_H ++ ++#include ++ ++#include ++ ++extern int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver); ++extern void drm_usb_exit(struct drm_driver *driver, struct usb_driver *udriver); ++ ++int drm_get_usb_dev(struct usb_interface *interface, ++ const struct usb_device_id *id, ++ struct drm_driver *driver); ++ ++#endif +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/mali_drm.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/mali_drm.h +new file mode 100644 +index 0000000..c438223 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/include/mali_drm.h +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __MALI_DRM_H__ ++#define __MALI_DRM_H__ ++ ++/* Mali specific ioctls */ ++#define NOT_USED_0_3 ++#define DRM_MALI_FB_ALLOC 0x04 ++#define DRM_MALI_FB_FREE 0x05 ++#define NOT_USED_6_12 ++#define DRM_MALI_MEM_INIT 0x13 ++#define DRM_MALI_MEM_ALLOC 0x14 ++#define DRM_MALI_MEM_FREE 0x15 ++#define DRM_MALI_FB_INIT 0x16 ++ ++#define DRM_IOCTL_MALI_FB_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_MALI_FB_ALLOC, drm_mali_mem_t) ++#define DRM_IOCTL_MALI_FB_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_MALI_FB_FREE, drm_mali_mem_t) ++#define DRM_IOCTL_MALI_MEM_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_MALI_MEM_INIT, drm_mali_mem_t) ++#define DRM_IOCTL_MALI_MEM_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_MALI_MEM_ALLOC, drm_mali_mem_t) ++#define DRM_IOCTL_MALI_MEM_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_MALI_MEM_FREE, drm_mali_mem_t) ++#define DRM_IOCTL_MALI_FB_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MALI_FB_INIT, drm_mali_fb_t) ++ ++typedef struct ++{ ++ int context; ++ unsigned int offset; ++ unsigned int size; ++ unsigned long free; ++} drm_mali_mem_t; ++ ++typedef struct ++{ ++ unsigned int offset, size; ++} drm_mali_fb_t; ++ ++#endif /* __MALI_DRM_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/Makefile b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/Makefile +new file mode 100644 +index 0000000..8f7c765 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/Makefile +@@ -0,0 +1,19 @@ ++# ++# Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++# ++# This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++# as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++# ++# A copy of the licence is included with the program, and can also be obtained from Free Software ++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++# ++# ++# Makefile for the drm device driver. This driver provides support for the ++# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ++ ++ccflags-y = -I include/drm ++mali_drm-y := mali_drv.o mali_mm.o ++ ++obj-$(CONFIG_DRM_MALI) += mali_drm.o ++ ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.c +new file mode 100644 +index 0000000..e3a75fc +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.c +@@ -0,0 +1,234 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include ++#include ++#include ++#include "drmP.h" ++#include "mali_drm.h" ++#include "mali_drv.h" ++ ++static struct platform_device *pdev; ++ ++static int mali_platform_drm_probe(struct platform_device *dev) ++{ ++ printk(KERN_INFO "DRM: mali_platform_drm_probe()\n"); ++ return mali_drm_init(dev); ++// return 0; ++} ++ ++static int mali_platform_drm_remove(struct platform_device *dev) ++{ ++ printk(KERN_INFO "DRM: mali_platform_drm_remove()\n"); ++ mali_drm_exit(dev); ++ return 0; ++} ++ ++static int mali_platform_drm_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ printk(KERN_INFO "DRM: mali_platform_drm_suspend()\n"); ++ return 0; ++} ++ ++static int mali_platform_drm_resume(struct platform_device *dev) ++{ ++ printk(KERN_INFO "DRM: mali_platform_drm_resume()\n"); ++ return 0; ++} ++ ++ ++static char mali_drm_device_name[] = "mali_drm"; ++static struct platform_driver platform_drm_driver = ++{ ++ .probe = mali_platform_drm_probe, ++ .remove = mali_platform_drm_remove, ++ .suspend = mali_platform_drm_suspend, ++ .resume = mali_platform_drm_resume, ++ .driver = { ++ .name = mali_drm_device_name, ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++#if 0 ++static const struct drm_device_id dock_device_ids[] = ++{ ++ {"MALIDRM", 0}, ++ {"", 0}, ++}; ++#endif ++ ++static int mali_driver_load(struct drm_device *dev, unsigned long chipset) ++{ ++ int ret; ++#if 0 ++ unsigned long base, size; ++#endif ++ drm_mali_private_t *dev_priv; ++ printk(KERN_ERR "DRM: mali_driver_load start\n"); ++ ++// dev_priv = drm_calloc(1, sizeof(drm_mali_private_t), DRM_MEM_DRIVER); ++// kcalloc ++// dev_priv = kmalloc(sizeof(drm_mali_private_t), GFP_KERNEL); ++// dev_priv = kzalloc(sizeof(drm_mali_private_t), GFP_KERNEL); ++ dev_priv = drm_calloc_large(1, sizeof(drm_mali_private_t)); ++ ++ if (dev_priv == NULL) ++ { ++ printk(KERN_INFO "DRM: No memory!\n"); ++ return -ENOMEM; ++ } ++ ++ dev->dev_private = (void *)dev_priv; ++ ++ if (NULL == dev->platformdev) ++ { ++ dev->platformdev = platform_device_register_simple(mali_drm_device_name, 0, NULL, 0); ++ pdev = dev->platformdev; ++ } ++ ++#if 0 ++ base = drm_get_resource_start(dev, 1); ++ size = drm_get_resource_len(dev, 1); ++#endif ++ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); ++ ++ if (ret) ++ { ++ printk(KERN_ERR "DRM: mali_driver_sman cant init\n"); ++// drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER); ++ drm_free_large(dev_priv); ++// kfree(dev_priv); ++ } ++ ++ //if ( ret ) kfree( dev_priv ); ++ ++ printk(KERN_ERR "DRM: mali_driver_load done\n"); ++ ++ return ret; ++} ++ ++static int mali_driver_unload(struct drm_device *dev) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ printk(KERN_ERR "DRM: mali_driver_unload start\n"); ++ ++ drm_sman_takedown(&dev_priv->sman); ++// drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); ++// kfree(dev_priv); ++ drm_free_large(dev_priv); ++ printk(KERN_ERR "DRM: mali_driver_unload done\n"); ++ ++ return 0; ++} ++ ++static const struct file_operations mali_drm_driver_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) ++ .ioctl = drm_ioctl, ++#else ++ .unlocked_ioctl = drm_ioctl, ++#endif ++ .mmap = drm_mmap, ++ .poll = drm_poll, ++// .read = drm_read, ++ .fasync = drm_fasync, ++}; ++ ++ ++static struct drm_driver driver = ++{ ++// .driver_features = DRIVER_USE_PLATFORM_DEVICE, ++// .driver_features = DRIVER_PRIME, ++ .driver_features = DRIVER_BUS_PLATFORM, ++ .load = mali_driver_load, ++ .unload = mali_driver_unload, ++ .context_dtor = NULL, ++ .dma_quiescent = mali_idle, ++ .reclaim_buffers = NULL, ++ .reclaim_buffers_idlelocked = mali_reclaim_buffers_locked, ++ .lastclose = mali_lastclose, ++// .get_map_ofs = drm_core_get_map_ofs, ++// .get_reg_ofs = drm_core_get_reg_ofs, ++ .ioctls = mali_ioctls, ++// .fops = { ++// .owner = THIS_MODULE, ++// .open = drm_open, ++// .release = drm_release, ++//#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) ++// .ioctl = drm_ioctl, ++//#else ++// .unlocked_ioctl = drm_ioctl, ++//#endif ++// .mmap = drm_mmap, ++// .poll = drm_poll, ++// .fasync = drm_fasync, ++// }, ++ .fops = &mali_drm_driver_fops, ++ .name = DRIVER_NAME, ++ .desc = DRIVER_DESC, ++ .date = DRIVER_DATE, ++ .major = DRIVER_MAJOR, ++ .minor = DRIVER_MINOR, ++ .patchlevel = DRIVER_PATCHLEVEL, ++}; ++ ++ ++ ++int mali_drm_init(struct platform_device *dev) ++{ ++ printk(KERN_INFO "mali_drm_init(), driver name: %s, version %d.%d\n", DRIVER_NAME, DRIVER_MAJOR, DRIVER_MINOR); ++ driver.num_ioctls = mali_max_ioctl; ++ driver.kdriver.platform_device = dev; ++ return drm_platform_init(&driver, dev); ++} ++ ++void mali_drm_exit(struct platform_device *dev) ++{ ++ drm_platform_exit(&driver, dev); ++} ++ ++ ++static int __init mali_init(void) ++{ ++ printk(KERN_INFO "mali_platform_drm_init(), driver name: %s, version %d.%d\n", DRIVER_NAME, DRIVER_MAJOR, DRIVER_MINOR); ++ driver.num_ioctls = mali_max_ioctl; ++// return drm_init(&driver); ++// return drm_pci_init(&driver, &platform_drm_driver); ++ ++ pdev = platform_device_register_simple(mali_drm_device_name, 0, NULL, 0); ++// platform_driver_register(&driver); ++ return platform_driver_register(&platform_drm_driver); ++ ++// driver.kdriver.platform_device = dev; ++// return drm_platform_init(&driver, dev); ++} ++ ++static void __exit mali_exit(void) ++{ ++// platform_device_unregister(pdev); ++// drm_exit(&driver); ++// drm_pci_exit(&driver, &platform_drm_driver); ++ ++ platform_driver_unregister(&platform_drm_driver); ++ platform_device_unregister(pdev); ++ ++// drm_platform_exit(&driver, dev); ++} ++ ++module_init(mali_init); ++module_exit(mali_exit); ++ ++MODULE_INFO(vermagic, VERMAGIC_STRING); ++MODULE_AUTHOR("ARM Ltd."); ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_LICENSE("GPL and additional rights"); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.h +new file mode 100644 +index 0000000..8bf2604 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_drv.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef _MALI_DRV_H_ ++#define _MALI_DRV_H_ ++ ++#define DRIVER_AUTHOR "ARM" ++#define DRIVER_NAME "mali_drm" ++#define DRIVER_DESC "DRM module for Mali-200, Mali-400" ++#define DRIVER_DATE "20100520" ++#define DRIVER_MAJOR 0 ++#define DRIVER_MINOR 1 ++#define DRIVER_PATCHLEVEL 0 ++ ++#include "drm_sman.h" ++ ++typedef struct drm_mali_private ++{ ++ drm_local_map_t *mmio; ++ unsigned int idle_fault; ++ struct drm_sman sman; ++ int vram_initialized; ++ unsigned long vram_offset; ++} drm_mali_private_t; ++ ++int mali_drm_init(struct platform_device *dev); ++void mali_drm_exit(struct platform_device *dev); ++ ++extern int mali_idle(struct drm_device *dev); ++extern void mali_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); ++extern void mali_lastclose(struct drm_device *dev); ++extern struct drm_ioctl_desc mali_ioctls[]; ++extern int mali_max_ioctl; ++ ++#define DRM_MEM_DRIVER 2 ++#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ ++ [DRM_IOCTL_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0} ++ ++#endif /* _MALI_DRV_H_ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_mm.c b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_mm.c +new file mode 100644 +index 0000000..27512aa +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm/mali/mali_mm.c +@@ -0,0 +1,262 @@ ++/* ++ * Copyright (C) 2010, 2012-2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "drmP.h" ++#include "mali_drm.h" ++#include "mali_drv.h" ++ ++#define VIDEO_TYPE 0 ++#define MEM_TYPE 1 ++ ++#define MALI_MM_ALIGN_SHIFT 4 ++#define MALI_MM_ALIGN_MASK ( (1 << MALI_MM_ALIGN_SHIFT) - 1) ++ ++ ++static void *mali_sman_mm_allocate(void *private, unsigned long size, unsigned alignment) ++{ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ return NULL; ++} ++ ++static void mali_sman_mm_free(void *private, void *ref) ++{ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++} ++ ++static void mali_sman_mm_destroy(void *private) ++{ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++} ++ ++static unsigned long mali_sman_mm_offset(void *private, void *ref) ++{ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ return ~((unsigned long)ref); ++} ++ ++static int mali_fb_init(struct drm_device *dev, void *data, struct drm_file *file_priv) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ drm_mali_fb_t *fb = data; ++ int ret; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ mutex_lock(&dev->struct_mutex); ++ { ++ struct drm_sman_mm sman_mm; ++ sman_mm.private = (void *)0xFFFFFFFF; ++ sman_mm.allocate = mali_sman_mm_allocate; ++ sman_mm.free = mali_sman_mm_free; ++ sman_mm.destroy = mali_sman_mm_destroy; ++ sman_mm.offset = mali_sman_mm_offset; ++ ret = drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm); ++ } ++ ++ if (ret) ++ { ++ DRM_ERROR("VRAM memory manager initialisation error\n"); ++ mutex_unlock(&dev->struct_mutex); ++ return ret; ++ } ++ ++ dev_priv->vram_initialized = 1; ++ dev_priv->vram_offset = fb->offset; ++ ++ mutex_unlock(&dev->struct_mutex); ++ DRM_DEBUG("offset = %u, size = %u\n", fb->offset, fb->size); ++ ++ return 0; ++} ++ ++static int mali_drm_alloc(struct drm_device *dev, struct drm_file *file_priv, void *data, int pool) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ drm_mali_mem_t *mem = data; ++ int retval = 0; ++ struct drm_memblock_item *item; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ if (0 == dev_priv->vram_initialized) ++ { ++ DRM_ERROR("Attempt to allocate from uninitialized memory manager.\n"); ++ mutex_unlock(&dev->struct_mutex); ++ return -EINVAL; ++ } ++ ++ mem->size = (mem->size + MALI_MM_ALIGN_MASK) >> MALI_MM_ALIGN_SHIFT; ++ item = drm_sman_alloc(&dev_priv->sman, pool, mem->size, 0, ++ (unsigned long)file_priv); ++ ++ mutex_unlock(&dev->struct_mutex); ++ ++ if (item) ++ { ++ mem->offset = dev_priv->vram_offset + (item->mm->offset(item->mm, item->mm_info) << MALI_MM_ALIGN_SHIFT); ++ mem->free = item->user_hash.key; ++ mem->size = mem->size << MALI_MM_ALIGN_SHIFT; ++ } ++ else ++ { ++ mem->offset = 0; ++ mem->size = 0; ++ mem->free = 0; ++ retval = -ENOMEM; ++ } ++ ++ DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem->size, mem->offset); ++ ++ return retval; ++} ++ ++static int mali_drm_free(struct drm_device *dev, void *data, struct drm_file *file_priv) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ drm_mali_mem_t *mem = data; ++ int ret; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ mutex_lock(&dev->struct_mutex); ++ ret = drm_sman_free_key(&dev_priv->sman, mem->free); ++ mutex_unlock(&dev->struct_mutex); ++ DRM_DEBUG("free = 0x%lx\n", mem->free); ++ ++ return ret; ++} ++ ++static int mali_fb_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) ++{ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ return mali_drm_alloc(dev, file_priv, data, VIDEO_TYPE); ++} ++ ++static int mali_ioctl_mem_init(struct drm_device *dev, void *data, struct drm_file *file_priv) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ drm_mali_mem_t *mem = data; ++ int ret; ++ dev_priv = dev->dev_private; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ mutex_lock(&dev->struct_mutex); ++ ret = drm_sman_set_range(&dev_priv->sman, MEM_TYPE, 0, mem->size >> MALI_MM_ALIGN_SHIFT); ++ ++ if (ret) ++ { ++ DRM_ERROR("MEM memory manager initialisation error\n"); ++ mutex_unlock(&dev->struct_mutex); ++ return ret; ++ } ++ ++ mutex_unlock(&dev->struct_mutex); ++ ++ return 0; ++} ++ ++static int mali_ioctl_mem_alloc(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ return mali_drm_alloc(dev, file_priv, data, MEM_TYPE); ++} ++ ++static drm_local_map_t *mem_reg_init(struct drm_device *dev) ++{ ++ struct drm_map_list *entry; ++ drm_local_map_t *map; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ list_for_each_entry(entry, &dev->maplist, head) ++ { ++ map = entry->map; ++ ++ if (!map) ++ { ++ continue; ++ } ++ ++ if (map->type == _DRM_REGISTERS) ++ { ++ return map; ++ } ++ } ++ return NULL; ++} ++ ++int mali_idle(struct drm_device *dev) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++// uint32_t idle_reg; ++// unsigned long end; ++// int i; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ if (dev_priv->idle_fault) ++ { ++ return 0; ++ } ++ ++ return 0; ++} ++ ++ ++void mali_lastclose(struct drm_device *dev) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ if (!dev_priv) ++ { ++ return; ++ } ++ ++ mutex_lock(&dev->struct_mutex); ++ drm_sman_cleanup(&dev_priv->sman); ++ dev_priv->vram_initialized = 0; ++ dev_priv->mmio = NULL; ++ mutex_unlock(&dev->struct_mutex); ++} ++ ++void mali_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv) ++{ ++ drm_mali_private_t *dev_priv = dev->dev_private; ++ printk(KERN_ERR "DRM: %s\n", __func__); ++ ++ mutex_lock(&dev->struct_mutex); ++ ++ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)file_priv)) ++ { ++ mutex_unlock(&dev->struct_mutex); ++ return; ++ } ++ ++ if (dev->driver->dma_quiescent) ++ { ++ dev->driver->dma_quiescent(dev); ++ } ++ ++ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); ++ mutex_unlock(&dev->struct_mutex); ++ return; ++} ++ ++struct drm_ioctl_desc mali_ioctls[] = ++{ ++ DRM_IOCTL_DEF(DRM_MALI_FB_ALLOC, mali_fb_alloc, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MALI_FB_FREE, mali_drm_free, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MALI_MEM_INIT, mali_ioctl_mem_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), ++ DRM_IOCTL_DEF(DRM_MALI_MEM_ALLOC, mali_ioctl_mem_alloc, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MALI_MEM_FREE, mali_drm_free, DRM_AUTH), ++ DRM_IOCTL_DEF(DRM_MALI_FB_INIT, mali_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY), ++}; ++ ++int mali_max_ioctl = DRM_ARRAY_SIZE(mali_ioctls); +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/readme b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/readme +new file mode 100644 +index 0000000..578d725 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/readme +@@ -0,0 +1,8 @@ ++How to build: ++KDIR=/work/kernel-2.6.35.7 make ++ ++How to install: ++insmod drm/drm.ko ++insmod mali_drm/mali_drm.ko ++insmod trunk/src/devicedrv/mali/mali.ko ++ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface.h +new file mode 100644 +index 0000000..99cc697 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface.h +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_interface.h ++ * ++ * This file contains the kernel space part of the UMP API. ++ */ ++ ++#ifndef __UMP_KERNEL_INTERFACE_H__ ++#define __UMP_KERNEL_INTERFACE_H__ ++ ++ ++/** @defgroup ump_kernel_space_api UMP Kernel Space API ++ * @{ */ ++ ++ ++#include "ump_kernel_platform.h" ++ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++/** ++ * External representation of a UMP handle in kernel space. ++ */ ++typedef void *ump_dd_handle; ++ ++/** ++ * Typedef for a secure ID, a system wide identificator for UMP memory buffers. ++ */ ++typedef unsigned int ump_secure_id; ++ ++ ++/** ++ * Value to indicate an invalid UMP memory handle. ++ */ ++#define UMP_DD_HANDLE_INVALID ((ump_dd_handle)0) ++ ++ ++/** ++ * Value to indicate an invalid secure Id. ++ */ ++#define UMP_INVALID_SECURE_ID ((ump_secure_id)-1) ++ ++ ++/** ++ * UMP error codes for kernel space. ++ */ ++typedef enum ++{ ++ UMP_DD_SUCCESS, /**< indicates success */ ++ UMP_DD_INVALID, /**< indicates failure */ ++} ump_dd_status_code; ++ ++ ++/** ++ * Struct used to describe a physical block used by UMP memory ++ */ ++typedef struct ump_dd_physical_block ++{ ++ unsigned long addr; /**< The physical address of the block */ ++ unsigned long size; /**< The length of the block, typically page aligned */ ++} ump_dd_physical_block; ++ ++ ++/** ++ * Retrieves the secure ID for the specified UMP memory. ++ * ++ * This identificator is unique across the entire system, and uniquely identifies ++ * the specified UMP memory. This identificator can later be used through the ++ * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id" or ++ * @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id" ++ * functions in order to access this UMP memory, for instance from another process. ++ * ++ * @note There is a user space equivalent function called @ref ump_secure_id_get "ump_secure_id_get" ++ * ++ * @see ump_dd_handle_create_from_secure_id ++ * @see ump_handle_create_from_secure_id ++ * @see ump_secure_id_get ++ * ++ * @param mem Handle to UMP memory. ++ * ++ * @return Returns the secure ID for the specified UMP memory. ++ */ ++UMP_KERNEL_API_EXPORT ump_secure_id ump_dd_secure_id_get(ump_dd_handle mem); ++ ++ ++/** ++ * Retrieves a handle to allocated UMP memory. ++ * ++ * The usage of UMP memory is reference counted, so this will increment the reference ++ * count by one for the specified UMP memory. ++ * Use @ref ump_dd_reference_release "ump_dd_reference_release" when there is no longer any ++ * use for the retrieved handle. ++ * ++ * @note There is a user space equivalent function called @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id" ++ * ++ * @see ump_dd_reference_release ++ * @see ump_handle_create_from_secure_id ++ * ++ * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get "ump_secure_id_get " function. ++ * ++ * @return UMP_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned. ++ */ ++UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_secure_id(ump_secure_id secure_id); ++ ++ ++/** ++ * Retrieves the number of physical blocks used by the specified UMP memory. ++ * ++ * This function retrieves the number of @ref ump_dd_physical_block "ump_dd_physical_block" structs needed ++ * to describe the physical memory layout of the given UMP memory. This can later be used when calling ++ * the functions @ref ump_dd_phys_blocks_get "ump_dd_phys_blocks_get" and ++ * @ref ump_dd_phys_block_get "ump_dd_phys_block_get". ++ * ++ * @see ump_dd_phys_blocks_get ++ * @see ump_dd_phys_block_get ++ * ++ * @param mem Handle to UMP memory. ++ * ++ * @return The number of ump_dd_physical_block structs required to describe the physical memory layout of the specified UMP memory. ++ */ ++UMP_KERNEL_API_EXPORT unsigned long ump_dd_phys_block_count_get(ump_dd_handle mem); ++ ++ ++/** ++ * Retrieves all physical memory block information for specified UMP memory. ++ * ++ * This function can be used by other device drivers in order to create MMU tables. ++ * ++ * @note This function will fail if the num_blocks parameter is either to large or to small. ++ * ++ * @see ump_dd_phys_block_get ++ * ++ * @param mem Handle to UMP memory. ++ * @param blocks An array of @ref ump_dd_physical_block "ump_dd_physical_block" structs that will receive the physical description. ++ * @param num_blocks The number of blocks to return in the blocks array. Use the function ++ * @ref ump_dd_phys_block_count_get "ump_dd_phys_block_count_get" first to determine the number of blocks required. ++ * ++ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure. ++ */ ++UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_blocks_get(ump_dd_handle mem, ump_dd_physical_block *blocks, unsigned long num_blocks); ++ ++ ++/** ++ * Retrieves the physical memory block information for specified block for the specified UMP memory. ++ * ++ * This function can be used by other device drivers in order to create MMU tables. ++ * ++ * @note This function will return UMP_DD_INVALID if the specified index is out of range. ++ * ++ * @see ump_dd_phys_blocks_get ++ * ++ * @param mem Handle to UMP memory. ++ * @param index Which physical info block to retrieve. ++ * @param block Pointer to a @ref ump_dd_physical_block "ump_dd_physical_block" struct which will receive the requested information. ++ * ++ * @return UMP_DD_SUCCESS indicates success, UMP_DD_INVALID indicates failure. ++ */ ++UMP_KERNEL_API_EXPORT ump_dd_status_code ump_dd_phys_block_get(ump_dd_handle mem, unsigned long index, ump_dd_physical_block *block); ++ ++ ++/** ++ * Retrieves the actual size of the specified UMP memory. ++ * ++ * The size is reported in bytes, and is typically page aligned. ++ * ++ * @note There is a user space equivalent function called @ref ump_size_get "ump_size_get" ++ * ++ * @see ump_size_get ++ * ++ * @param mem Handle to UMP memory. ++ * ++ * @return Returns the allocated size of the specified UMP memory, in bytes. ++ */ ++UMP_KERNEL_API_EXPORT unsigned long ump_dd_size_get(ump_dd_handle mem); ++ ++ ++/** ++ * Adds an extra reference to the specified UMP memory. ++ * ++ * This function adds an extra reference to the specified UMP memory. This function should ++ * be used every time a UMP memory handle is duplicated, that is, assigned to another ump_dd_handle ++ * variable. The function @ref ump_dd_reference_release "ump_dd_reference_release" must then be used ++ * to release each copy of the UMP memory handle. ++ * ++ * @note You are not required to call @ref ump_dd_reference_add "ump_dd_reference_add" ++ * for UMP handles returned from ++ * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id", ++ * because these handles are already reference counted by this function. ++ * ++ * @note There is a user space equivalent function called @ref ump_reference_add "ump_reference_add" ++ * ++ * @see ump_reference_add ++ * ++ * @param mem Handle to UMP memory. ++ */ ++UMP_KERNEL_API_EXPORT void ump_dd_reference_add(ump_dd_handle mem); ++ ++ ++/** ++ * Releases a reference from the specified UMP memory. ++ * ++ * This function should be called once for every reference to the UMP memory handle. ++ * When the last reference is released, all resources associated with this UMP memory ++ * handle are freed. ++ * ++ * @note There is a user space equivalent function called @ref ump_reference_release "ump_reference_release" ++ * ++ * @see ump_reference_release ++ * ++ * @param mem Handle to UMP memory. ++ */ ++UMP_KERNEL_API_EXPORT void ump_dd_reference_release(ump_dd_handle mem); ++ ++ ++#ifdef __cplusplus ++} ++#endif ++ ++ ++/** @} */ /* end group ump_kernel_space_api */ ++ ++ ++#endif /* __UMP_KERNEL_INTERFACE_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface_ref_drv.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface_ref_drv.h +new file mode 100644 +index 0000000..8a65302 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_interface_ref_drv.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2010, 2013 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_interface.h ++ */ ++ ++#ifndef __UMP_KERNEL_INTERFACE_REF_DRV_H__ ++#define __UMP_KERNEL_INTERFACE_REF_DRV_H__ ++ ++#include "ump_kernel_interface.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** Turn specified physical memory into UMP memory. */ ++UMP_KERNEL_API_EXPORT ump_dd_handle ump_dd_handle_create_from_phys_blocks(ump_dd_physical_block *blocks, unsigned long num_blocks); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* __UMP_KERNEL_INTERFACE_REF_DRV_H__ */ +diff --git a/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_platform.h b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_platform.h +new file mode 100644 +index 0000000..1b5af40 +--- /dev/null ++++ b/modules/mali/DX910-SW-99002-r4p0-00rel0_modify/driver/src/ump/include/ump/ump_kernel_platform.h +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2010 ARM Limited. All rights reserved. ++ * ++ * This program is free software and is provided to you under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence. ++ * ++ * A copy of the licence is included with the program, and can also be obtained from Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * @file ump_kernel_platform.h ++ * ++ * This file should define UMP_KERNEL_API_EXPORT, ++ * which dictates how the UMP kernel API should be exported/imported. ++ * Modify this file, if needed, to match your platform setup. ++ */ ++ ++#ifndef __UMP_KERNEL_PLATFORM_H__ ++#define __UMP_KERNEL_PLATFORM_H__ ++ ++/** @addtogroup ump_kernel_space_api ++ * @{ */ ++ ++/** ++ * A define which controls how UMP kernel space API functions are imported and exported. ++ * This define should be set by the implementor of the UMP API. ++ */ ++ ++#if defined(_WIN32) ++ ++#if defined(UMP_BUILDING_UMP_LIBRARY) ++#define UMP_KERNEL_API_EXPORT __declspec(dllexport) ++#else ++#define UMP_KERNEL_API_EXPORT __declspec(dllimport) ++#endif ++ ++#else ++ ++#define UMP_KERNEL_API_EXPORT ++ ++#endif ++ ++ ++/** @} */ /* end group ump_kernel_space_api */ ++ ++ ++#endif /* __UMP_KERNEL_PLATFORM_H__ */ +diff --git a/modules/mali/Makefile b/modules/mali/Makefile +index 26143c6..2d0b1e9 100755 +--- a/modules/mali/Makefile ++++ b/modules/mali/Makefile +@@ -2,8 +2,9 @@ PWD=$(shell pwd) + + include ../../.config + +-MALI_DRV_ROOT=DX910-SW-99002-r4p0-00rel0/driver/src/devicedrv/mali +-MALI_UMP_ROOT=DX910-SW-99002-r4p0-00rel0/driver/src/devicedrv/ump ++MALI_DRV_ROOT=DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/mali ++MALI_UMP_ROOT=DX910-SW-99002-r4p0-00rel0_modify/driver/src/devicedrv/ump ++MALI_EGL_ROOT=DX910-SW-99002-r4p0-00rel0_modify/driver/src/egl/x11/drm_module/mali_drm + + ifeq ($(LICHEE_PLATFORM),linux) + UMP_ENABLE=1 +@@ -12,9 +13,10 @@ UMP_ENABLE=0 + endif + + install: build +- cp $(MALI_DRV_ROOT)/mali.ko $(LICHEE_MOD_DIR)/ ++ cp $(MALI_DRV_ROOT)/mali.ko $(LICHEE_MOD_DIR)/kernel/drivers/gpu/mali ++ cp $(MALI_EGL_ROOT)/mali_drm.ko $(LICHEE_MOD_DIR)/kernel/drivers/gpu/mali + if [ $(UMP_ENABLE) -eq 1 ]; then \ +- cp $(MALI_UMP_ROOT)/ump.ko $(LICHEE_MOD_DIR)/; \ ++ cp $(MALI_UMP_ROOT)/ump.ko $(LICHEE_MOD_DIR)/kernel/drivers/gpu/ump; \ + fi + + build: +@@ -26,6 +28,7 @@ build: + fi + $(MAKE) -j16 -C $(MALI_DRV_ROOT) USING_MMU=1 USING_UMP=$(UMP_ENABLE) USING_PMM=1 BUILD=release \ + KDIR=${LICHEE_KDIR} ++ $(MAKE) -j16 -C $(MALI_EGL_ROOT) CONFIG=ca8-virtex820-m400-1 BUILD=release KDIR=${LICHEE_KDIR}; \ + + clean: + if [ $(UMP_ENABLE) -eq 1 ]; then \ +@@ -33,3 +36,5 @@ clean: + fi + $(MAKE) -C $(MALI_DRV_ROOT) USING_MMU=1 USING_UMP=$(UMP_ENABLE) USING_PMM=1 BUILD=release \ + KDIR=${LICHEE_KDIR} clean ++ $(MAKE) -C $(MALI_EGL_ROOT) USING_MMU=1 BUILD=release KDIR=${LICHEE_KDIR} clean ++ diff --git a/scripts/armbianmonitor/armbianmonitor b/scripts/armbianmonitor/armbianmonitor index e6eb50ca70..f3fbf88cb5 100644 --- a/scripts/armbianmonitor/armbianmonitor +++ b/scripts/armbianmonitor/armbianmonitor @@ -651,6 +651,7 @@ BAKBQCAQCAQCgUAgEAgEwjPhPzou6T0AoAAA" | base64 --decode | tar xzf - CollectSupportInfo() { cat /var/log/armhwinfo.log echo -e "\n### dmesg now:\n\n$(dmesg | tail -n 250)" + ls /tmp/armbianmonitor_checks_* >/dev/null 2>&1 || return for file in /tmp/armbianmonitor_checks_* ; do echo -e "\n### \c" ls "${file}" | cut -f1 -d.