mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-04 02:02:28 +09:00
drivers/gpu: merge in Mali GPU drivers from AMLogic
Change-Id: I8ba9513faf15eacb9df45e820bb276be34871a74 Signed-off-by: Dongjin Kim <tobetter@gmail.com>
This commit is contained in:
committed by
Dongjin Kim
parent
0e31135fba
commit
f01201789a
284
drivers/gpu/arm/mali/Kbuild
Executable file
284
drivers/gpu/arm/mali/Kbuild
Executable file
@@ -0,0 +1,284 @@
|
||||
#
|
||||
# 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.
|
||||
############## Kasin Added, for platform. ################
|
||||
TARGET_PLATFORM:=meson_m450
|
||||
ifeq ($(CONFIG_ARCH_MESON1),y)
|
||||
TARGET_PLATFORM:= meson_m400
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_MESON3),y)
|
||||
TARGET_PLATFORM:= meson_m400
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_MESON6),y)
|
||||
TARGET_PLATFORM:= meson_m400
|
||||
endif
|
||||
ifeq ($(CONFIG_ARCH_MESON6TV),y)
|
||||
TARGET_PLATFORM:= meson_m400
|
||||
endif
|
||||
##################### end Kasin Added. ###################
|
||||
|
||||
# set up defaults if not defined by the user
|
||||
TIMESTAMP ?= default
|
||||
ifeq ($(CONFIG_UMP), m)
|
||||
USING_UMP ?= 1
|
||||
else
|
||||
USING_UMP ?= 0
|
||||
endif
|
||||
|
||||
ifneq ($(KBUILD_SRC),)
|
||||
ifneq ($(wildcard $(KBUILD_SRC)/$(src)),)
|
||||
TOP_KBUILD_SRC := $(KBUILD_SRC)/
|
||||
endif
|
||||
endif
|
||||
|
||||
OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 16
|
||||
|
||||
USING_GPU_UTILIZATION ?= 1
|
||||
|
||||
PROFILING_SKIP_PP_JOBS ?= 0
|
||||
PROFILING_SKIP_PP_AND_GP_JOBS ?= 0
|
||||
############## Kasin Added, for platform. ################
|
||||
ifeq ($(CONFIG_MALI400_DEBUG),y)
|
||||
BUILD ?= debug
|
||||
else
|
||||
BUILD ?= release
|
||||
ldflags-y += --strip-debug
|
||||
endif
|
||||
##################### end Kasin Added. ###################
|
||||
|
||||
############## Kasin Added, useless now. ################
|
||||
ifeq ($(USING_UMP),1)
|
||||
UMP_SYMVERS_FILE = ../ump/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS = $(srctree)/$(src)/$(UMP_SYMVERS_FILE)
|
||||
endif
|
||||
##################### end Kasin Added. ###################
|
||||
|
||||
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
|
||||
|
||||
############## Kasin Added, useless now. ################
|
||||
# Get path to driver source from Linux build system
|
||||
DRIVER_DIR=$(src)
|
||||
##################### end Kasin Added. ###################
|
||||
|
||||
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
|
||||
ccflags-y += -I$(TOP_KBUILD_SRC)$(DRIVER_DIR)/linux/license/gpl
|
||||
|
||||
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 += \
|
||||
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
|
||||
|
||||
############## Kasin Added, for platform. ################
|
||||
mali-y += \
|
||||
platform/meson_main.o \
|
||||
platform/mali_pm_device.o \
|
||||
platform/mali_clock.o \
|
||||
platform/mpgpu.o \
|
||||
|
||||
ifeq ($(TARGET_PLATFORM),meson_m400)
|
||||
MALI_PLATFORM_FILES:= \
|
||||
platform/meson_m400/mali_fix.o \
|
||||
platform/meson_m400/mali_platform.o \
|
||||
platform/meson_m400/platform_mx.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_PLATFORM),meson_m450)
|
||||
ccflags-y += -DCONFIG_MALI450=y
|
||||
mali-y += \
|
||||
platform/meson_m450/scaling.o
|
||||
|
||||
mali-$(CONFIG_ARCH_MESON8) += \
|
||||
platform/meson_m450/platform_m8.o
|
||||
|
||||
mali-$(CONFIG_ARCH_MESON6TVD) += \
|
||||
platform/meson_m450/platform_m6tvd.o
|
||||
|
||||
mali-$(CONFIG_ARCH_MESON8B) += \
|
||||
platform/meson_m450/platform_m8b.o
|
||||
|
||||
mali-$(CONFIG_ARCH_MESONG9TV) += \
|
||||
platform/meson_m450/platform_g9tv.o
|
||||
endif
|
||||
##################### end Kasin Added. ###################
|
||||
|
||||
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)
|
||||
ccflags-y += -DMALI_FAKE_PLATFORM_DEVICE
|
||||
|
||||
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
|
||||
ccflags-y += -I$(srctree)/drivers/staging/android
|
||||
|
||||
# Get subversion revision number, fall back to only ${MALI_RELEASE_NAME} if no svn info is available
|
||||
MALI_RELEASE_NAME=$(shell cat $(TOP_KBUILD_SRC)$(DRIVER_DIR)/.version 2> /dev/null)
|
||||
|
||||
SVN_INFO = (cd $(TOP_KBUILD_SRC)$(DRIVER_DIR); 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 $(TOP_KBUILD_SRC)$(DRIVER_DIR); git describe --always 2>/dev/null)
|
||||
ifneq ($(GIT_REV),)
|
||||
# Git detected
|
||||
DRIVER_REV := $(MALI_RELEASE_NAME)-$(GIT_REV)
|
||||
CHANGE_DATE := $(shell cd $(TOP_KBUILD_SRC)$(DRIVER_DIR); git log -1 --format="%ci")
|
||||
CHANGED_REVISION := $(GIT_REV)
|
||||
REPO_URL := $(shell cd $(TOP_KBUILD_SRC)$(DRIVER_DIR); 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 $(TOP_KBUILD_SRC)$(DRIVER_DIR); 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
|
||||
$(TOP_KBUILD_SRC)$(DRIVER_DIR)/__malidrv_build_info.c:
|
||||
@echo 'const char *__malidrv_build_info(void) { return "malidrv: $(VERSION_STRINGS)";}' > $(TOP_KBUILD_SRC)$(DRIVER_DIR)/__malidrv_build_info.c
|
||||
102
drivers/gpu/arm/mali/Kconfig
Executable file
102
drivers/gpu/arm/mali/Kconfig
Executable file
@@ -0,0 +1,102 @@
|
||||
menu "Mali GPU OpenGL device driver"
|
||||
config MALI400
|
||||
tristate "Mali-300/400/450 support"
|
||||
depends on ARM
|
||||
depends on m
|
||||
default m
|
||||
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 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_EXTRA_SUPPORT
|
||||
bool "Select other items in kernel to support PROFILING."
|
||||
depends on MALI400_PROFILING
|
||||
select PROFILING
|
||||
select FTRACE
|
||||
select PERF_EVENTS
|
||||
select ENABLE_DEFAULT_TRACERS
|
||||
select DEBUG_MUTEXES
|
||||
select HIGH_RES_TIMERS
|
||||
select HW_PERF_EVENTS
|
||||
select CPU_FREQ
|
||||
|
||||
config MALI400_PROFILING
|
||||
bool "Enable Mali profiling"
|
||||
depends on MALI400
|
||||
select MALI400_DEBUG
|
||||
select TRACEPOINTS
|
||||
default n
|
||||
---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
|
||||
default y
|
||||
---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.
|
||||
|
||||
if ARCH_MESON6
|
||||
config MESON6_GPU_EXTRA
|
||||
bool "M6 fix"
|
||||
depends on MALI400
|
||||
default y
|
||||
select MALI_SHARED_INTERRUPTS
|
||||
endif
|
||||
|
||||
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.
|
||||
|
||||
endmenu
|
||||
159
drivers/gpu/arm/mali/Makefile
Normal file
159
drivers/gpu/arm/mali/Makefile
Normal file
@@ -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
|
||||
1
drivers/gpu/arm/mali/__malidrv_build_info.c
Normal file
1
drivers/gpu/arm/mali/__malidrv_build_info.c
Normal file
@@ -0,0 +1 @@
|
||||
const char *__malidrv_build_info(void) { return "malidrv: API_VERSION=401 REPO_URL=heads/odroidc_2014.05 REVISION=-2014.05-3-gf4cc986 CHANGED_REVISION=2014.05-3-gf4cc986 CHANGE_DATE=2014-09-22 15:09:31 +0900 BUILD_DATE=Seg Out 13 07:21:28 BRT 2014 BUILD=release TARGET_PLATFORM=meson_m450 MALI_PLATFORM= KDIR= OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB=16 USING_UMP=y USING_PROFILING= USING_INTERNAL_PROFILING= USING_GPU_UTILIZATION=1 USING_POWER_PERFORMANCE_POLICY= MALI_UPPER_HALF_SCHEDULING=1";}
|
||||
27
drivers/gpu/arm/mali/aml.dtd
Normal file
27
drivers/gpu/arm/mali/aml.dtd
Normal file
@@ -0,0 +1,27 @@
|
||||
/// ***************************************************************************************
|
||||
/// - MALI
|
||||
//$$ MODULE="MALI"
|
||||
//$$ DEVICE="mali"
|
||||
//$$ L2 PROP_STR = "status"
|
||||
mali{
|
||||
compatible = "arm,mali";
|
||||
dev_name = "mali";
|
||||
status = "ok";
|
||||
|
||||
//$$ L2 PROP_U32 = "dvfs_id"
|
||||
//$$ L2 PROP_U32 = "recorde_number"
|
||||
//$$ L2 PROP_U32 = "dvfs_table"
|
||||
cfg {
|
||||
shared_memory = <1024>; /** Mbyte **/
|
||||
dvfs_size = <5>; /** must be correct count for dvfs_table */
|
||||
dvfs_table = <
|
||||
/* NOTE: frequent in this table must be ascending order */
|
||||
/* freq_idx volage_index min max */
|
||||
0 0 0 200
|
||||
1 1 152 205
|
||||
2 2 180 212
|
||||
3 3 205 236
|
||||
4 4 230 256
|
||||
>;
|
||||
};
|
||||
};
|
||||
124
drivers/gpu/arm/mali/common/mali_broadcast.c
Normal file
124
drivers/gpu/arm/mali/common/mali_broadcast.c
Normal file
@@ -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);
|
||||
}
|
||||
52
drivers/gpu/arm/mali/common/mali_broadcast.h
Normal file
52
drivers/gpu/arm/mali/common/mali_broadcast.h
Normal file
@@ -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);
|
||||
}
|
||||
209
drivers/gpu/arm/mali/common/mali_dlbu.c
Normal file
209
drivers/gpu/arm/mali/common/mali_dlbu.c
Normal file
@@ -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);
|
||||
|
||||
}
|
||||
46
drivers/gpu/arm/mali/common/mali_dlbu.h
Normal file
46
drivers/gpu/arm/mali/common/mali_dlbu.h
Normal file
@@ -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__ */
|
||||
201
drivers/gpu/arm/mali/common/mali_dma.c
Normal file
201
drivers/gpu/arm/mali/common/mali_dma.c
Normal file
@@ -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;
|
||||
}
|
||||
190
drivers/gpu/arm/mali/common/mali_dma.h
Normal file
190
drivers/gpu/arm/mali/common/mali_dma.h
Normal file
@@ -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__ */
|
||||
337
drivers/gpu/arm/mali/common/mali_gp.c
Normal file
337
drivers/gpu/arm/mali/common/mali_gp.c
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
93
drivers/gpu/arm/mali/common/mali_gp.h
Normal file
93
drivers/gpu/arm/mali/common/mali_gp.h
Normal file
@@ -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__ */
|
||||
131
drivers/gpu/arm/mali/common/mali_gp_job.c
Normal file
131
drivers/gpu/arm/mali/common/mali_gp_job.c
Normal file
@@ -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;
|
||||
}
|
||||
186
drivers/gpu/arm/mali/common/mali_gp_job.h
Normal file
186
drivers/gpu/arm/mali/common/mali_gp_job.h
Normal file
@@ -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__ */
|
||||
701
drivers/gpu/arm/mali/common/mali_gp_scheduler.c
Normal file
701
drivers/gpu/arm/mali/common/mali_gp_scheduler.c
Normal file
@@ -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 <linux/sched.h>
|
||||
#include <trace/events/gpu.h>
|
||||
#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();
|
||||
}
|
||||
}
|
||||
101
drivers/gpu/arm/mali/common/mali_gp_scheduler.h
Normal file
101
drivers/gpu/arm/mali/common/mali_gp_scheduler.h
Normal file
@@ -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__ */
|
||||
1912
drivers/gpu/arm/mali/common/mali_group.c
Executable file
1912
drivers/gpu/arm/mali/common/mali_group.c
Executable file
File diff suppressed because it is too large
Load Diff
309
drivers/gpu/arm/mali/common/mali_group.h
Executable file
309
drivers/gpu/arm/mali/common/mali_group.h
Executable file
@@ -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__ */
|
||||
45
drivers/gpu/arm/mali/common/mali_hw_core.c
Normal file
45
drivers/gpu/arm/mali/common/mali_hw_core.c
Normal file
@@ -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);
|
||||
}
|
||||
100
drivers/gpu/arm/mali/common/mali_hw_core.h
Normal file
100
drivers/gpu/arm/mali/common/mali_hw_core.h
Normal file
@@ -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__ */
|
||||
175
drivers/gpu/arm/mali/common/mali_kernel_common.h
Normal file
175
drivers/gpu/arm/mali/common/mali_kernel_common.h
Normal file
@@ -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__ */
|
||||
1399
drivers/gpu/arm/mali/common/mali_kernel_core.c
Normal file
1399
drivers/gpu/arm/mali/common/mali_kernel_core.c
Normal file
File diff suppressed because it is too large
Load Diff
56
drivers/gpu/arm/mali/common/mali_kernel_core.h
Normal file
56
drivers/gpu/arm/mali/common/mali_kernel_core.h
Normal file
@@ -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__ */
|
||||
173
drivers/gpu/arm/mali/common/mali_kernel_descriptor_mapping.c
Normal file
173
drivers/gpu/arm/mali/common/mali_kernel_descriptor_mapping.c
Normal file
@@ -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);
|
||||
}
|
||||
99
drivers/gpu/arm/mali/common/mali_kernel_descriptor_mapping.h
Normal file
99
drivers/gpu/arm/mali/common/mali_kernel_descriptor_mapping.h
Normal file
@@ -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__ */
|
||||
439
drivers/gpu/arm/mali/common/mali_kernel_utilization.c
Normal file
439
drivers/gpu/arm/mali/common/mali_kernel_utilization.c
Normal file
@@ -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;
|
||||
}
|
||||
65
drivers/gpu/arm/mali/common/mali_kernel_utilization.h
Executable file
65
drivers/gpu/arm/mali/common/mali_kernel_utilization.h
Executable file
@@ -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 <linux/mali/mali_utgard.h>
|
||||
#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__ */
|
||||
49
drivers/gpu/arm/mali/common/mali_kernel_vsync.c
Normal file
49
drivers/gpu/arm/mali/common/mali_kernel_vsync.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
585
drivers/gpu/arm/mali/common/mali_l2_cache.c
Executable file
585
drivers/gpu/arm/mali/common/mali_l2_cache.c
Executable file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
if (cache && cache->pm_domain && cache->pm_domain->state == MALI_PM_DOMAIN_OFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
89
drivers/gpu/arm/mali/common/mali_l2_cache.h
Executable file
89
drivers/gpu/arm/mali/common/mali_l2_cache.h
Executable file
@@ -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__ */
|
||||
69
drivers/gpu/arm/mali/common/mali_mem_validation.c
Normal file
69
drivers/gpu/arm/mali/common/mali_mem_validation.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 0
|
||||
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;
|
||||
#else
|
||||
return _MALI_OSK_ERR_OK;
|
||||
#endif
|
||||
}
|
||||
19
drivers/gpu/arm/mali/common/mali_mem_validation.h
Normal file
19
drivers/gpu/arm/mali/common/mali_mem_validation.h
Normal file
@@ -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__ */
|
||||
431
drivers/gpu/arm/mali/common/mali_mmu.c
Executable file
431
drivers/gpu/arm/mali/common/mali_mmu.c
Executable file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* 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
|
||||
123
drivers/gpu/arm/mali/common/mali_mmu.h
Executable file
123
drivers/gpu/arm/mali/common/mali_mmu.h
Executable file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/io.h>
|
||||
#include <mach/am_regs.h>
|
||||
#include <linux/module.h>
|
||||
#if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6
|
||||
#include "meson_m400/mali_fix.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* 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__ */
|
||||
436
drivers/gpu/arm/mali/common/mali_mmu_page_directory.c
Normal file
436
drivers/gpu/arm/mali/common/mali_mmu_page_directory.c
Normal file
@@ -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;
|
||||
}
|
||||
107
drivers/gpu/arm/mali/common/mali_mmu_page_directory.h
Normal file
107
drivers/gpu/arm/mali/common/mali_mmu_page_directory.h
Normal file
@@ -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__ */
|
||||
1335
drivers/gpu/arm/mali/common/mali_osk.h
Normal file
1335
drivers/gpu/arm/mali/common/mali_osk.h
Normal file
File diff suppressed because it is too large
Load Diff
162
drivers/gpu/arm/mali/common/mali_osk_bitops.h
Normal file
162
drivers/gpu/arm/mali/common/mali_osk_bitops.h
Normal file
@@ -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__ */
|
||||
273
drivers/gpu/arm/mali/common/mali_osk_list.h
Normal file
273
drivers/gpu/arm/mali/common/mali_osk_list.h
Normal file
@@ -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__ */
|
||||
118
drivers/gpu/arm/mali/common/mali_osk_mali.h
Normal file
118
drivers/gpu/arm/mali/common/mali_osk_mali.h
Normal file
@@ -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 <linux/mali/mali_utgard.h>
|
||||
#include <mali_osk.h>
|
||||
|
||||
#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__ */
|
||||
141
drivers/gpu/arm/mali/common/mali_osk_profiling.h
Normal file
141
drivers/gpu/arm/mali/common/mali_osk_profiling.h
Normal file
@@ -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__ */
|
||||
|
||||
|
||||
455
drivers/gpu/arm/mali/common/mali_osk_types.h
Normal file
455
drivers/gpu/arm/mali/common/mali_osk_types.h
Normal file
@@ -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 <linux/types.h>
|
||||
#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__ */
|
||||
122
drivers/gpu/arm/mali/common/mali_pm.c
Normal file
122
drivers/gpu/arm/mali/common/mali_pm.c
Normal file
@@ -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;
|
||||
}
|
||||
28
drivers/gpu/arm/mali/common/mali_pm.h
Normal file
28
drivers/gpu/arm/mali/common/mali_pm.h
Normal file
@@ -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__ */
|
||||
241
drivers/gpu/arm/mali/common/mali_pm_domain.c
Normal file
241
drivers/gpu/arm/mali/common/mali_pm_domain.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
74
drivers/gpu/arm/mali/common/mali_pm_domain.h
Normal file
74
drivers/gpu/arm/mali/common/mali_pm_domain.h
Normal file
@@ -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__ */
|
||||
444
drivers/gpu/arm/mali/common/mali_pmu.c
Executable file
444
drivers/gpu/arm/mali/common/mali_pmu.c
Executable file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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;
|
||||
u32 active_mask;
|
||||
u32 mask_ck;
|
||||
u32 swt_dly;
|
||||
u32 xxd = 1;
|
||||
|
||||
_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
|
||||
active_mask = mask & stat;
|
||||
mask_ck = active_mask;
|
||||
swt_dly = 0xfff;
|
||||
for (current_domain = 1; current_domain <= pmu->registered_cores_mask; current_domain <<= 1) {
|
||||
if (current_domain & active_mask) {
|
||||
if (mask_ck == 1) {
|
||||
swt_dly = pmu->switch_delay;
|
||||
xxd = 0;
|
||||
}
|
||||
mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_SW_DELAY, swt_dly);
|
||||
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;
|
||||
}
|
||||
}
|
||||
mask_ck = mask_ck >> 1;
|
||||
}
|
||||
if (xxd != 0) {
|
||||
printk("@@@@ warn\n");
|
||||
printk("mask_ck:%d,active_mask:%d\n", mask_ck, active_mask);
|
||||
//panic(0);
|
||||
}
|
||||
if (swt_dly != pmu->switch_delay)
|
||||
mali_hw_core_register_write_relaxed(&pmu->hw_core, PMU_REG_ADDR_MGMT_SW_DELAY, pmu->switch_delay);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* kasin.li@amlogic.com.
|
||||
**/
|
||||
|
||||
u32 mali_pmu_get_status(void)
|
||||
{
|
||||
u32 ret;
|
||||
MALI_DEBUG_ASSERT_POINTER(mali_global_pmu_core);
|
||||
mali_pmu_lock(mali_global_pmu_core);
|
||||
ret = mali_hw_core_register_read(&mali_global_pmu_core->hw_core, PMU_REG_ADDR_MGMT_STATUS);
|
||||
mali_pmu_unlock(mali_global_pmu_core);
|
||||
return ret;
|
||||
|
||||
}
|
||||
139
drivers/gpu/arm/mali/common/mali_pmu.h
Normal file
139
drivers/gpu/arm/mali/common/mali_pmu.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* 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);
|
||||
/** @brief Retrieves the Mali Power Domain status.
|
||||
*
|
||||
* @return the Mali Power Domain status 1 off, 0 on.
|
||||
*/
|
||||
extern u32 mali_pmu_get_status(void);
|
||||
|
||||
#endif /* __MALI_PMU_H__ */
|
||||
573
drivers/gpu/arm/mali/common/mali_pp.c
Normal file
573
drivers/gpu/arm/mali/common/mali_pp.c
Normal file
@@ -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
|
||||
131
drivers/gpu/arm/mali/common/mali_pp.h
Normal file
131
drivers/gpu/arm/mali/common/mali_pp.h
Normal file
@@ -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__ */
|
||||
278
drivers/gpu/arm/mali/common/mali_pp_job.c
Normal file
278
drivers/gpu/arm/mali/common/mali_pp_job.c
Normal file
@@ -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];
|
||||
}
|
||||
392
drivers/gpu/arm/mali/common/mali_pp_job.h
Executable file
392
drivers/gpu/arm/mali/common/mali_pp_job.h
Executable file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* 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 <linux/version.h>
|
||||
#ifdef CONFIG_SYNC
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,10)
|
||||
#include <sync.h>
|
||||
#else
|
||||
#include <linux/sync.h>
|
||||
#endif
|
||||
#endif
|
||||
#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__ */
|
||||
2067
drivers/gpu/arm/mali/common/mali_pp_scheduler.c
Executable file
2067
drivers/gpu/arm/mali/common/mali_pp_scheduler.c
Executable file
File diff suppressed because it is too large
Load Diff
130
drivers/gpu/arm/mali/common/mali_pp_scheduler.h
Normal file
130
drivers/gpu/arm/mali/common/mali_pp_scheduler.h
Normal file
@@ -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__ */
|
||||
112
drivers/gpu/arm/mali/common/mali_scheduler.c
Normal file
112
drivers/gpu/arm/mali/common/mali_scheduler.c
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
90
drivers/gpu/arm/mali/common/mali_scheduler.h
Normal file
90
drivers/gpu/arm/mali/common/mali_scheduler.h
Normal file
@@ -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__ */
|
||||
34
drivers/gpu/arm/mali/common/mali_scheduler_types.h
Normal file
34
drivers/gpu/arm/mali/common/mali_scheduler_types.h
Normal file
@@ -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__ */
|
||||
81
drivers/gpu/arm/mali/common/mali_session.c
Normal file
81
drivers/gpu/arm/mali/common/mali_session.c
Normal file
@@ -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
|
||||
94
drivers/gpu/arm/mali/common/mali_session.h
Normal file
94
drivers/gpu/arm/mali/common/mali_session.h
Normal file
@@ -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__ */
|
||||
464
drivers/gpu/arm/mali/common/mali_soft_job.c
Normal file
464
drivers/gpu/arm/mali/common/mali_soft_job.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
196
drivers/gpu/arm/mali/common/mali_soft_job.h
Normal file
196
drivers/gpu/arm/mali/common/mali_soft_job.h
Normal file
@@ -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__ */
|
||||
77
drivers/gpu/arm/mali/common/mali_spinlock_reentrant.c
Normal file
77
drivers/gpu/arm/mali/common/mali_spinlock_reentrant.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
70
drivers/gpu/arm/mali/common/mali_spinlock_reentrant.h
Normal file
70
drivers/gpu/arm/mali/common/mali_spinlock_reentrant.h
Normal file
@@ -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__ */
|
||||
1374
drivers/gpu/arm/mali/common/mali_timeline.c
Normal file
1374
drivers/gpu/arm/mali/common/mali_timeline.c
Normal file
File diff suppressed because it is too large
Load Diff
494
drivers/gpu/arm/mali/common/mali_timeline.h
Normal file
494
drivers/gpu/arm/mali/common/mali_timeline.h
Normal file
@@ -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__ */
|
||||
198
drivers/gpu/arm/mali/common/mali_timeline_fence_wait.c
Normal file
198
drivers/gpu/arm/mali/common/mali_timeline_fence_wait.c
Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
67
drivers/gpu/arm/mali/common/mali_timeline_fence_wait.h
Normal file
67
drivers/gpu/arm/mali/common/mali_timeline_fence_wait.h
Normal file
@@ -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__ */
|
||||
158
drivers/gpu/arm/mali/common/mali_timeline_sync_fence.c
Normal file
158
drivers/gpu/arm/mali/common/mali_timeline_sync_fence.c
Normal file
@@ -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) */
|
||||
51
drivers/gpu/arm/mali/common/mali_timeline_sync_fence.h
Normal file
51
drivers/gpu/arm/mali/common/mali_timeline_sync_fence.h
Normal file
@@ -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__ */
|
||||
614
drivers/gpu/arm/mali/common/mali_ukk.h
Normal file
614
drivers/gpu/arm/mali/common/mali_ukk.h
Normal file
@@ -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__ */
|
||||
146
drivers/gpu/arm/mali/common/mali_user_settings_db.c
Normal file
146
drivers/gpu/arm/mali/common/mali_user_settings_db.c
Normal file
@@ -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;
|
||||
}
|
||||
39
drivers/gpu/arm/mali/common/mali_user_settings_db.h
Normal file
39
drivers/gpu/arm/mali/common/mali_user_settings_db.h
Normal file
@@ -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__ */
|
||||
418
drivers/gpu/arm/mali/include/linux/mali/mali_utgard.h
Normal file
418
drivers/gpu/arm/mali/include/linux/mali/mali_utgard.h
Normal file
@@ -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
|
||||
261
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_counters.h
Normal file
261
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_counters.h
Normal file
@@ -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_*/
|
||||
95
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_ioctl.h
Normal file
95
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_ioctl.h
Normal file
@@ -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 <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/fs.h> /* 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__ */
|
||||
@@ -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_*/
|
||||
@@ -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__ */
|
||||
1132
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_uk_types.h
Normal file
1132
drivers/gpu/arm/mali/include/linux/mali/mali_utgard_uk_types.h
Normal file
File diff suppressed because it is too large
Load Diff
30
drivers/gpu/arm/mali/linux/license/gpl/mali_kernel_license.h
Normal file
30
drivers/gpu/arm/mali/linux/license/gpl/mali_kernel_license.h
Normal file
@@ -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__ */
|
||||
38
drivers/gpu/arm/mali/linux/mali_device_pause_resume.c
Normal file
38
drivers/gpu/arm/mali/linux/mali_device_pause_resume.c
Normal file
@@ -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 <linux/module.h>
|
||||
#include <linux/mali/mali_utgard.h>
|
||||
#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);
|
||||
830
drivers/gpu/arm/mali/linux/mali_kernel_linux.c
Executable file
830
drivers/gpu/arm/mali/linux/mali_kernel_linux.c
Executable file
@@ -0,0 +1,830 @@
|
||||
/**
|
||||
* 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 <linux/module.h> /* kernel module definitions */
|
||||
#include <linux/fs.h> /* file system operations */
|
||||
#include <linux/cdev.h> /* character device definitions */
|
||||
#include <linux/mm.h> /* memory manager definitions */
|
||||
#include <linux/mali/mali_utgard_ioctl.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/device.h>
|
||||
#include "mali_kernel_license.h"
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/mali/mali_utgard.h>
|
||||
#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 */
|
||||
|
||||
/* from the __malidrv_build_info.c file that is generated during build */
|
||||
extern const char *__malidrv_build_info(void);
|
||||
extern int mali_pdev_dts_init(struct platform_device* mali_gpu_device);
|
||||
|
||||
/* 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 <linux/cpumask.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/smp.h>
|
||||
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
|
||||
|
||||
/* 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
|
||||
|
||||
#ifdef CONFIG_USE_OF
|
||||
static const struct of_device_id amlogic_mesonstream_dt_match[]={
|
||||
{ .compatible = "arm,mali",
|
||||
},
|
||||
{},
|
||||
};
|
||||
#else
|
||||
#define amlogic_mesonstream_dt_match NULL
|
||||
#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
|
||||
|
||||
#ifdef CONFIG_USE_OF
|
||||
.of_match_table = amlogic_mesonstream_dt_match,
|
||||
#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
|
||||
|
||||
extern int mpgpu_class_init(void);
|
||||
extern void mpgpu_class_exit(void);
|
||||
|
||||
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
|
||||
|
||||
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"));
|
||||
|
||||
mpgpu_class_init();
|
||||
|
||||
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
|
||||
|
||||
mpgpu_class_exit();
|
||||
|
||||
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;
|
||||
|
||||
#ifndef MALI_FAKE_PLATFORM_DEVICE
|
||||
if (mali_pdev_dts_init(pdev) < 0)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
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();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mali_driver_resume_scheduler(struct device *dev)
|
||||
{
|
||||
mali_pm_os_resume();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int mali_driver_runtime_suspend(struct device *dev)
|
||||
{
|
||||
mali_pm_runtime_suspend();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mali_driver_runtime_resume(struct device *dev)
|
||||
{
|
||||
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);
|
||||
33
drivers/gpu/arm/mali/linux/mali_kernel_linux.h
Executable file
33
drivers/gpu/arm/mali/linux/mali_kernel_linux.h
Executable file
@@ -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 <linux/cdev.h> /* 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__ */
|
||||
1393
drivers/gpu/arm/mali/linux/mali_kernel_sysfs.c
Executable file
1393
drivers/gpu/arm/mali/linux/mali_kernel_sysfs.c
Executable file
File diff suppressed because it is too large
Load Diff
29
drivers/gpu/arm/mali/linux/mali_kernel_sysfs.h
Executable file
29
drivers/gpu/arm/mali/linux/mali_kernel_sysfs.h
Executable file
@@ -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 <linux/device.h>
|
||||
|
||||
#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__ */
|
||||
126
drivers/gpu/arm/mali/linux/mali_linux_trace.h
Normal file
126
drivers/gpu/arm/mali/linux/mali_linux_trace.h
Normal file
@@ -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 <linux/types.h>
|
||||
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/tracepoint.h>
|
||||
|
||||
#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 <trace/define_trace.h>
|
||||
|
||||
353
drivers/gpu/arm/mali/linux/mali_memory.c
Normal file
353
drivers/gpu/arm/mali/linux/mali_memory.c
Normal file
@@ -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 <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
134
drivers/gpu/arm/mali/linux/mali_memory.h
Normal file
134
drivers/gpu/arm/mali/linux/mali_memory.h
Normal file
@@ -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 <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#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__ */
|
||||
319
drivers/gpu/arm/mali/linux/mali_memory_block_alloc.c
Normal file
319
drivers/gpu/arm/mali/linux/mali_memory_block_alloc.c
Normal file
@@ -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 <linux/mutex.h>
|
||||
#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;
|
||||
}
|
||||
29
drivers/gpu/arm/mali/linux/mali_memory_block_alloc.h
Normal file
29
drivers/gpu/arm/mali/linux/mali_memory_block_alloc.h
Normal file
@@ -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__ */
|
||||
434
drivers/gpu/arm/mali/linux/mali_memory_dma_buf.c
Normal file
434
drivers/gpu/arm/mali/linux/mali_memory_dma_buf.c
Normal file
@@ -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 <linux/fs.h> /* file system operations */
|
||||
#include <asm/uaccess.h> /* user space access */
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
40
drivers/gpu/arm/mali/linux/mali_memory_dma_buf.h
Normal file
40
drivers/gpu/arm/mali/linux/mali_memory_dma_buf.h
Normal file
@@ -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__ */
|
||||
127
drivers/gpu/arm/mali/linux/mali_memory_external.c
Normal file
127
drivers/gpu/arm/mali/linux/mali_memory_external.c
Normal file
@@ -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;
|
||||
}
|
||||
556
drivers/gpu/arm/mali/linux/mali_memory_os_alloc.c
Normal file
556
drivers/gpu/arm/mali/linux/mali_memory_os_alloc.c
Normal file
@@ -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 <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#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_KERNEL);
|
||||
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;
|
||||
}
|
||||
47
drivers/gpu/arm/mali/linux/mali_memory_os_alloc.h
Normal file
47
drivers/gpu/arm/mali/linux/mali_memory_os_alloc.h
Normal file
@@ -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__ */
|
||||
100
drivers/gpu/arm/mali/linux/mali_memory_types.h
Normal file
100
drivers/gpu/arm/mali/linux/mali_memory_types.h
Normal file
@@ -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__ */
|
||||
215
drivers/gpu/arm/mali/linux/mali_memory_ump.c
Normal file
215
drivers/gpu/arm/mali/linux/mali_memory_ump.c
Normal file
@@ -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;
|
||||
}
|
||||
60
drivers/gpu/arm/mali/linux/mali_osk_atomics.c
Normal file
60
drivers/gpu/arm/mali/linux/mali_osk_atomics.c
Normal file
@@ -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 <asm/atomic.h>
|
||||
#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);
|
||||
}
|
||||
216
drivers/gpu/arm/mali/linux/mali_osk_irq.c
Executable file
216
drivers/gpu/arm/mali/linux/mali_osk_irq.c
Executable file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 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 <linux/types.h>
|
||||
#include <mach/cpu.h>
|
||||
#include <linux/slab.h> /* For memory allocation */
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#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 MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6
|
||||
u32 get_irqnum(struct _mali_osk_irq_t_struct* irq)
|
||||
{
|
||||
if (irq)
|
||||
return irq->irqnum;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#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;
|
||||
}
|
||||
281
drivers/gpu/arm/mali/linux/mali_osk_locks.c
Normal file
281
drivers/gpu/arm/mali/linux/mali_osk_locks.c
Normal file
@@ -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 */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user