mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-30 15:48:52 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
193
drivers/gpu/arm/t72x/r7p0/Kbuild
Normal file
193
drivers/gpu/arm/t72x/r7p0/Kbuild
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
#
|
||||
# (C) COPYRIGHT 2012,2014 ARM Limited. All rights reserved.
|
||||
#
|
||||
# This program is free software and is provided to you under the terms of the
|
||||
# GNU General Public License version 2 as published by the Free Software
|
||||
# Foundation, and any use by you of this program is subject to the terms
|
||||
# of such GNU licence.
|
||||
#
|
||||
# A copy of the licence is included with the program, and can also be obtained
|
||||
# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
|
||||
# Driver version string which is returned to userspace via an ioctl
|
||||
MALI_RELEASE_NAME ?= "r7p0-03rel0"
|
||||
|
||||
# Paths required for build
|
||||
KBASE_PATH = $(src)
|
||||
KBASE_PLATFORM_PATH = $(KBASE_PATH)/platform_dummy
|
||||
UMP_PATH = $(src)/../../../base
|
||||
|
||||
ifeq ($(CONFIG_MALI_ERROR_INJECTION),y)
|
||||
MALI_ERROR_INJECT_ON = 1
|
||||
endif
|
||||
|
||||
# Set up defaults if not defined by build system
|
||||
MALI_CUSTOMER_RELEASE ?= 1
|
||||
MALI_UNIT_TEST ?= 0
|
||||
MALI_KERNEL_TEST_API ?= 0
|
||||
MALI_ERROR_INJECT_ON ?= 0
|
||||
MALI_MOCK_TEST ?= 0
|
||||
MALI_COVERAGE ?= 0
|
||||
MALI_INSTRUMENTATION_LEVEL ?= 0
|
||||
# MALI_SEC_SECURE_RENDERING
|
||||
MALI_SUPPORT_ASP_SECURE ?= 0
|
||||
# This workaround is for what seems to be a compiler bug we observed in
|
||||
# GCC 4.7 on AOSP 4.3. The bug caused an intermittent failure compiling
|
||||
# the "_Pragma" syntax, where an error message is returned:
|
||||
#
|
||||
# "internal compiler error: unspellable token PRAGMA"
|
||||
#
|
||||
# This regression has thus far only been seen on the GCC 4.7 compiler bundled
|
||||
# with AOSP 4.3.0. So this makefile, intended for in-tree kernel builds
|
||||
# which are not known to be used with AOSP, is hardcoded to disable the
|
||||
# workaround, i.e. set the define to 0.
|
||||
MALI_GCC_WORKAROUND_MIDCOM_4598 ?= 0
|
||||
|
||||
# Set up our defines, which will be passed to gcc
|
||||
DEFINES = \
|
||||
-DMALI_CUSTOMER_RELEASE=$(MALI_CUSTOMER_RELEASE) \
|
||||
-DMALI_KERNEL_TEST_API=$(MALI_KERNEL_TEST_API) \
|
||||
-DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \
|
||||
-DMALI_ERROR_INJECT_ON=$(MALI_ERROR_INJECT_ON) \
|
||||
-DMALI_MOCK_TEST=$(MALI_MOCK_TEST) \
|
||||
-DMALI_COVERAGE=$(MALI_COVERAGE) \
|
||||
-DMALI_INSTRUMENTATION_LEVEL=$(MALI_INSTRUMENTATION_LEVEL) \
|
||||
-DMALI_RELEASE_NAME=\"$(MALI_RELEASE_NAME)\" \
|
||||
-DMALI_GCC_WORKAROUND_MIDCOM_4598=$(MALI_GCC_WORKAROUND_MIDCOM_4598) \
|
||||
-DMALI_SEC_CL_BOOST \
|
||||
-DMALI_SEC_FENCE_INTEGRATION \
|
||||
-DMALI_SEC_UTILIZATION \
|
||||
-DKBASE_FENCE_TIMEOUT_FAKE_SIGNAL \
|
||||
-DMALI_SEC_ASP_SECURE_RENDERING=$(MALI_SUPPORT_ASP_SECURE)
|
||||
|
||||
ifeq ($(CONFIG_MALI_GATOR_SUPPORT_TIMELINE_T72X),y)
|
||||
DEFINES +=-DCONFIG_MALI_GATOR_SUPPORT
|
||||
endif
|
||||
|
||||
ifeq ($(KBUILD_EXTMOD),)
|
||||
# in-tree
|
||||
DEFINES +=-DMALI_KBASE_THIRDPARTY_PATH=../../$(src)/platform/$(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)
|
||||
else
|
||||
# out-of-tree
|
||||
DEFINES +=-DMALI_KBASE_THIRDPARTY_PATH=$(src)/platform/$(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME)
|
||||
endif
|
||||
|
||||
DEFINES += -I$(srctree)/drivers/staging/android
|
||||
|
||||
ifeq ($(CONFIG_MALI_SEC_HWCNT),y)
|
||||
DEFINES +=-DMALI_SEC_HWCNT
|
||||
endif
|
||||
|
||||
DEFINES += -I$(srctree)/drivers/soc/samsung/pwrcal
|
||||
|
||||
# Use our defines when compiling
|
||||
ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(UMP_PATH) -I$(srctree)/include/linux
|
||||
subdir-ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(OSK_PATH) -I$(UMP_PATH) -I$(srctree)/include/linux
|
||||
|
||||
SRC := \
|
||||
mali_kbase_device.c \
|
||||
mali_kbase_cache_policy.c \
|
||||
mali_kbase_mem.c \
|
||||
mali_kbase_mmu.c \
|
||||
mali_kbase_ipa.c \
|
||||
mali_kbase_jd.c \
|
||||
mali_kbase_jd_debugfs.c \
|
||||
mali_kbase_jm.c \
|
||||
mali_kbase_gpuprops.c \
|
||||
mali_kbase_js.c \
|
||||
mali_kbase_js_ctx_attr.c \
|
||||
mali_kbase_event.c \
|
||||
mali_kbase_context.c \
|
||||
mali_kbase_pm.c \
|
||||
mali_kbase_config.c \
|
||||
mali_kbase_security.c \
|
||||
mali_kbase_instr.c \
|
||||
mali_kbase_vinstr.c \
|
||||
mali_kbase_softjobs.c \
|
||||
mali_kbase_10969_workaround.c \
|
||||
mali_kbase_hw.c \
|
||||
mali_kbase_utility.c \
|
||||
mali_kbase_debug.c \
|
||||
mali_kbase_trace_timeline.c \
|
||||
mali_kbase_gpu_memory_debugfs.c \
|
||||
mali_kbase_mem_linux.c \
|
||||
mali_kbase_core_linux.c \
|
||||
mali_kbase_sync.c \
|
||||
mali_kbase_sync_user.c \
|
||||
mali_kbase_replay.c \
|
||||
mali_kbase_mem_profile_debugfs.c \
|
||||
mali_kbase_mmu_mode_lpae.c \
|
||||
mali_kbase_disjoint_events.c \
|
||||
mali_kbase_gator_api.c \
|
||||
mali_kbase_debug_mem_view.c \
|
||||
mali_kbase_debug_job_fault.c \
|
||||
mali_kbase_smc.c \
|
||||
mali_kbase_mem_pool.c \
|
||||
mali_kbase_mem_pool_debugfs.c
|
||||
|
||||
ifeq ($(CONFIG_MALI_MIPE_ENABLED_T72X),y)
|
||||
SRC += mali_kbase_tlstream.c
|
||||
ifeq ($(MALI_UNIT_TEST),1)
|
||||
SRC += mali_kbase_tlstream_test.c
|
||||
endif
|
||||
endif
|
||||
|
||||
# Job Scheduler Policy: Completely Fair Scheduler
|
||||
SRC += mali_kbase_js_policy_cfs.c
|
||||
|
||||
ccflags-y += -I$(KBASE_PATH)
|
||||
|
||||
|
||||
ifeq ($(CONFIG_MALI_PLATFORM_THIRDPARTY),y)
|
||||
# remove begin and end quotes from the Kconfig string type
|
||||
platform_name := $(shell echo $(CONFIG_MALI_PLATFORM_THIRDPARTY_NAME))
|
||||
MALI_PLATFORM_THIRDPARTY_DIR := platform/exynos
|
||||
ccflags-y += -I$(src)/$(MALI_PLATFORM_THIRDPARTY_DIR)
|
||||
ifeq ($(CONFIG_MALI_R7P0_T72X),m)
|
||||
include $(src)/platform/$(platform_name)/Kbuild
|
||||
else ifeq ($(CONFIG_MALI_R7P0_T72X),y)
|
||||
obj-$(CONFIG_MALI_R7P0_T72X) += platform/
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MALI_PLATFORM_DEVICETREE),y)
|
||||
SRC += platform/devicetree/mali_kbase_runtime_pm.c
|
||||
SRC += platform/devicetree/mali_kbase_config_devicetree.c
|
||||
ccflags-y += -I$(src)/platform/devicetree
|
||||
endif
|
||||
|
||||
# Tell the Linux build system from which .o file to create the kernel module
|
||||
obj-$(CONFIG_MALI_R7P0_T72X) += mali_kbase.o
|
||||
|
||||
# Tell the Linux build system to enable building of our .c files
|
||||
mali_kbase-y := $(SRC:.c=.o)
|
||||
|
||||
ifneq ($(wildcard $(src)/internal/Kbuild),)
|
||||
ifeq ($(MALI_CUSTOMER_RELEASE),0)
|
||||
# This include may set MALI_BACKEND_PATH and CONFIG_MALI_BACKEND_REAL
|
||||
include $(src)/internal/Kbuild
|
||||
mali_kbase-y += $(INTERNAL:.c=.o)
|
||||
endif
|
||||
endif
|
||||
|
||||
MALI_BACKEND_PATH ?= backend
|
||||
CONFIG_MALI_BACKEND ?= gpu
|
||||
CONFIG_MALI_BACKEND_REAL ?= $(CONFIG_MALI_BACKEND)
|
||||
|
||||
ifeq ($(MALI_MOCK_TEST),1)
|
||||
ifeq ($(CONFIG_MALI_BACKEND_REAL),gpu)
|
||||
# Test functionality
|
||||
mali_kbase-y += tests/internal/src/mock/mali_kbase_pm_driver_mock.o
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL)/Kbuild
|
||||
mali_kbase-y += $(BACKEND:.c=.o)
|
||||
|
||||
ccflags-y += -I$(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL)
|
||||
subdir-ccflags-y += -I$(src)/$(MALI_BACKEND_PATH)/$(CONFIG_MALI_BACKEND_REAL)
|
||||
216
drivers/gpu/arm/t72x/r7p0/Kconfig
Normal file
216
drivers/gpu/arm/t72x/r7p0/Kconfig
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
#
|
||||
# (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
#
|
||||
# This program is free software and is provided to you under the terms of the
|
||||
# GNU General Public License version 2 as published by the Free Software
|
||||
# Foundation, and any use by you of this program is subject to the terms
|
||||
# of such GNU licence.
|
||||
#
|
||||
# A copy of the licence is included with the program, and can also be obtained
|
||||
# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
choice
|
||||
prompt "Streamline support"
|
||||
depends on MALI_R7P0_T72X
|
||||
default MALI_TIMELINE_DISABLED_T72X
|
||||
help
|
||||
Select streamline support configuration.
|
||||
|
||||
config MALI_TIMELINE_DISABLED_T72X
|
||||
bool "Streamline support disabled"
|
||||
depends on MALI_R7P0_T72X
|
||||
help
|
||||
Disable support for ARM Streamline Performance Analyzer.
|
||||
|
||||
Timeline support will not be included in
|
||||
kernel code.
|
||||
Debug stream will not be generated.
|
||||
|
||||
config MALI_GATOR_SUPPORT_TIMELINE_T72X
|
||||
bool "Streamline support via Gator"
|
||||
depends on MALI_R7P0_T72X
|
||||
help
|
||||
Adds diagnostic support for use with the ARM Streamline Performance Analyzer.
|
||||
You will need the Gator device driver already loaded before loading this driver when enabling
|
||||
Streamline debug support.
|
||||
|
||||
config MALI_MIPE_ENABLED_T72X
|
||||
bool "Streamline support via MIPE"
|
||||
depends on MALI_R7P0_T72X
|
||||
help
|
||||
Adds diagnostic support for use with the ARM Streamline Performance Analyzer.
|
||||
|
||||
Stream will be transmitted directly to Mali GPU library.
|
||||
Compatible version of the library is required to read debug stream generated by kernel.
|
||||
|
||||
endchoice
|
||||
|
||||
# { SRUK-MALI_SYSTRACE_SUPPORT
|
||||
config MALI_SYSTRACE_SUPPORT
|
||||
bool "systrace Debug support"
|
||||
depends on MALI_T72X
|
||||
default y
|
||||
help
|
||||
Enable systrace marker in kernel
|
||||
# SRUK-MALI_SYSTRACE_SUPPORT }
|
||||
|
||||
config MALI_DVFS
|
||||
bool "Enable DVFS"
|
||||
depends on MALI_T72X
|
||||
default n
|
||||
help
|
||||
Choose this option to enable DVFS in the Mali Midgard DDK.
|
||||
|
||||
config MALI_DVFS_USER
|
||||
bool "Enable DVFS USER"
|
||||
depends on MALI_T72X && MALI_DVFS
|
||||
default n
|
||||
help
|
||||
Choose this option to enable DVFS_USER on MALI t8xx DDK.
|
||||
|
||||
config MALI_RT_PM
|
||||
bool "Enable Runtime power management"
|
||||
depends on MALI_T72X
|
||||
depends on PM_RUNTIME
|
||||
default y
|
||||
help
|
||||
Choose this option to enable runtime power management in the Mali Midgard DDK.
|
||||
|
||||
config MALI_MIDGARD_ENABLE_TRACE
|
||||
bool "Enable kbase tracing"
|
||||
depends on MALI_T72X
|
||||
default n
|
||||
help
|
||||
Enables tracing in kbase. Trace log available through
|
||||
the "mali_trace" debugfs file, when the CONFIG_DEBUG_FS is enabled
|
||||
|
||||
config MALI_EXYNOS_TRACE
|
||||
bool "Enable kbase tracing"
|
||||
depends on MALI_T72X
|
||||
default y
|
||||
help
|
||||
Enables tracing in kbase. Trace log available through
|
||||
the "mali_trace" debugfs file, when the CONFIG_DEBUG_FS is enabled
|
||||
|
||||
config MALI_DEBUG_SYS
|
||||
bool "Enable sysfs for the Mali Midgard DDK "
|
||||
depends on MALI_T72X && SYSFS
|
||||
default n
|
||||
help
|
||||
Enables sysfs for the Mali Midgard DDK. Set/Monitor the Mali Midgard DDK
|
||||
|
||||
config MALI_DEVFREQ
|
||||
bool "devfreq support for Mali"
|
||||
depends on MALI_T72X && PM_DEVFREQ
|
||||
help
|
||||
Support devfreq for Mali.
|
||||
|
||||
Using the devfreq framework and, by default, the simpleondemand
|
||||
governor, the frequency of Mali will be dynamically selected from the
|
||||
available OPPs.
|
||||
|
||||
|
||||
# MALI_EXPERT configuration options
|
||||
|
||||
menuconfig MALI_EXPERT
|
||||
depends on MALI_T72X
|
||||
bool "Enable Expert Settings"
|
||||
default n
|
||||
help
|
||||
Enabling this option and modifying the default settings may produce a driver with performance or
|
||||
other limitations.
|
||||
|
||||
config MALI_DEBUG_SHADER_SPLIT_FS
|
||||
bool "Allow mapping of shader cores via sysfs"
|
||||
depends on MALI_T72X && MALI_DEBUG_SYS && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
Select this option to provide a sysfs entry for runtime configuration of shader
|
||||
core affinity masks.
|
||||
|
||||
config MALI_PLATFORM_FAKE
|
||||
bool "Enable fake platform device support"
|
||||
depends on MALI_T72X && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
When you start to work with the Mali Midgard series device driver the platform-specific code of
|
||||
the Linux kernel for your platform may not be complete. In this situation the kernel device driver
|
||||
supports creating the platform device outside of the Linux platform-specific code.
|
||||
Enable this option if would like to use a platform device configuration from within the device driver.
|
||||
|
||||
config MALI_PLATFORM_THIRDPARTY
|
||||
depends on MALI_T72X
|
||||
bool "Third Party Platform"
|
||||
default y
|
||||
help
|
||||
Select the SOC platform that contains a Mali-T8XX
|
||||
|
||||
config MALI_PLATFORM_THIRDPARTY_NAME
|
||||
depends on MALI_T72X && MALI_PLATFORM_THIRDPARTY && MALI_EXPERT
|
||||
string "Third party platform name"
|
||||
help
|
||||
Enter the name of a third party platform that is supported. The third part configuration
|
||||
file must be in midgard/config/tpip/mali_kbase_config_xxx.c where xxx is the name
|
||||
specified here.
|
||||
|
||||
config MALI_DEBUG
|
||||
bool "Debug build"
|
||||
depends on MALI_T72X && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
Select this option for increased checking and reporting of errors.
|
||||
|
||||
config MALI_NO_MALI
|
||||
bool "No Mali"
|
||||
depends on MALI_T72X && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
This can be used to test the driver in a simulated environment
|
||||
whereby the hardware is not physically present. If the hardware is physically
|
||||
present it will not be used. This can be used to test the majority of the
|
||||
driver without needing actual hardware or for software benchmarking.
|
||||
All calls to the simulated hardware will complete immediately as if the hardware
|
||||
completed the task.
|
||||
|
||||
config MALI_ERROR_INJECT
|
||||
bool "Error injection"
|
||||
depends on MALI_T72X && MALI_EXPERT && MALI_NO_MALI
|
||||
default n
|
||||
help
|
||||
Enables insertion of errors to test module failure and recovery mechanisms.
|
||||
|
||||
config MALI_TRACE_TIMELINE
|
||||
bool "Timeline tracing"
|
||||
depends on MALI_T72X && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
Enables timeline tracing through the kernel tracepoint system.
|
||||
|
||||
config MALI_SYSTEM_TRACE
|
||||
bool "Enable system event tracing support"
|
||||
depends on MALI_T72X && MALI_EXPERT
|
||||
default n
|
||||
help
|
||||
Choose this option to enable system trace events for each
|
||||
kbase event. This is typically used for debugging but has
|
||||
minimal overhead when not in use. Enable only if you know what
|
||||
you are doing.
|
||||
|
||||
config MALI_GPU_TRACEPOINTS
|
||||
bool "Enable GPU tracepoints"
|
||||
depends on MALI_T72X && ANDROID
|
||||
select GPU_TRACEPOINTS
|
||||
help
|
||||
Enables GPU tracepoints using Android trace event definitions.
|
||||
|
||||
config MALI_SEC_HWCNT
|
||||
bool "Enable sec hwcnt feature"
|
||||
depends on MALI_T72X
|
||||
default n
|
||||
help
|
||||
Enable sec hwcnt feature.
|
||||
|
||||
source "drivers/gpu/arm/t8xx/r7p0/platform/Kconfig"
|
||||
46
drivers/gpu/arm/t72x/r7p0/Makefile
Normal file
46
drivers/gpu/arm/t72x/r7p0/Makefile
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#
|
||||
# (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
#
|
||||
# This program is free software and is provided to you under the terms of the
|
||||
# GNU General Public License version 2 as published by the Free Software
|
||||
# Foundation, and any use by you of this program is subject to the terms
|
||||
# of such GNU licence.
|
||||
#
|
||||
# A copy of the licence is included with the program, and can also be obtained
|
||||
# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
BUSLOG_PATH_RELATIVE = $(CURDIR)/../../../..
|
||||
UMP_PATH_RELATIVE = $(CURDIR)/../../../base/ump
|
||||
KBASE_PATH_RELATIVE = $(CURDIR)
|
||||
KDS_PATH_RELATIVE = $(CURDIR)/../../../..
|
||||
EXTRA_SYMBOLS = $(UMP_PATH_RELATIVE)/src/Module.symvers
|
||||
|
||||
ifeq ($(MALI_UNIT_TEST), 1)
|
||||
EXTRA_SYMBOLS += $(KBASE_PATH_RELATIVE)/tests/internal/src/kernel_assert_module/linux/Module.symvers
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard $(CURDIR)/internal/Makefile.in),)
|
||||
include $(CURDIR)/internal/Makefile.in
|
||||
endif
|
||||
|
||||
ifeq ($(MALI_BUS_LOG), 1)
|
||||
#Add bus logger symbols
|
||||
EXTRA_SYMBOLS += $(BUSLOG_PATH_RELATIVE)/drivers/base/bus_logger/Module.symvers
|
||||
endif
|
||||
|
||||
# GPL driver supports KDS
|
||||
EXTRA_SYMBOLS += $(KDS_PATH_RELATIVE)/drivers/base/kds/Module.symvers
|
||||
|
||||
# we get the symbols from modules using KBUILD_EXTRA_SYMBOLS to prevent warnings about unknown functions
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(CURDIR) EXTRA_CFLAGS="-I$(CURDIR)/../../../../include -I$(CURDIR)/../../../../tests/include $(SCONS_CFLAGS)" $(SCONS_CONFIGS) KBUILD_EXTRA_SYMBOLS="$(EXTRA_SYMBOLS)" modules
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
|
||||
58
drivers/gpu/arm/t72x/r7p0/backend/gpu/Kbuild
Normal file
58
drivers/gpu/arm/t72x/r7p0/backend/gpu/Kbuild
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
#
|
||||
# This program is free software and is provided to you under the terms of the
|
||||
# GNU General Public License version 2 as published by the Free Software
|
||||
# Foundation, and any use by you of this program is subject to the terms
|
||||
# of such GNU licence.
|
||||
#
|
||||
# A copy of the licence is included with the program, and can also be obtained
|
||||
# from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
BACKEND += \
|
||||
backend/gpu/mali_kbase_cache_policy_backend.c \
|
||||
backend/gpu/mali_kbase_device_hw.c \
|
||||
backend/gpu/mali_kbase_gpu.c \
|
||||
backend/gpu/mali_kbase_gpuprops_backend.c \
|
||||
backend/gpu/mali_kbase_debug_job_fault_backend.c \
|
||||
backend/gpu/mali_kbase_irq_linux.c \
|
||||
backend/gpu/mali_kbase_instr_backend.c \
|
||||
backend/gpu/mali_kbase_jm_as.c \
|
||||
backend/gpu/mali_kbase_jm_hw.c \
|
||||
backend/gpu/mali_kbase_jm_rb.c \
|
||||
backend/gpu/mali_kbase_js_affinity.c \
|
||||
backend/gpu/mali_kbase_js_backend.c \
|
||||
backend/gpu/mali_kbase_mmu_hw_direct.c \
|
||||
backend/gpu/mali_kbase_pm_backend.c \
|
||||
backend/gpu/mali_kbase_pm_driver.c \
|
||||
backend/gpu/mali_kbase_pm_metrics.c \
|
||||
backend/gpu/mali_kbase_pm_ca.c \
|
||||
backend/gpu/mali_kbase_pm_ca_fixed.c \
|
||||
backend/gpu/mali_kbase_pm_always_on.c \
|
||||
backend/gpu/mali_kbase_pm_coarse_demand.c \
|
||||
backend/gpu/mali_kbase_pm_demand.c \
|
||||
backend/gpu/mali_kbase_pm_policy.c \
|
||||
backend/gpu/mali_kbase_time.c
|
||||
|
||||
ifeq ($(MALI_CUSTOMER_RELEASE),0)
|
||||
BACKEND += \
|
||||
backend/gpu/mali_kbase_pm_ca_random.c \
|
||||
backend/gpu/mali_kbase_pm_demand_always_powered.c \
|
||||
backend/gpu/mali_kbase_pm_fast_start.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MALI_DEVFREQ),y)
|
||||
BACKEND += backend/gpu/mali_kbase_devfreq.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MALI_NO_MALI),y)
|
||||
# Dummy model
|
||||
BACKEND += backend/gpu/mali_kbase_model_dummy.c
|
||||
BACKEND += backend/gpu/mali_kbase_model_linux.c
|
||||
# HW error simulation
|
||||
BACKEND += backend/gpu/mali_kbase_model_error_generator.c
|
||||
endif
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend specific configuration
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_BACKEND_CONFIG_H_
|
||||
#define _KBASE_BACKEND_CONFIG_H_
|
||||
|
||||
/* Enable GPU reset API */
|
||||
#define KBASE_GPU_RESET_EN 1
|
||||
|
||||
#endif /* _KBASE_BACKEND_CONFIG_H_ */
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 "backend/gpu/mali_kbase_cache_policy_backend.h"
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_CACHE_POLICY_BACKEND_H_
|
||||
#define _KBASE_CACHE_POLICY_BACKEND_H_
|
||||
|
||||
#include "mali_kbase.h"
|
||||
#include "mali_base_kernel.h"
|
||||
|
||||
|
||||
#endif /* _KBASE_CACHE_POLICY_H_ */
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
#include "mali_kbase_debug_job_fault.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
/*GPU_CONTROL_REG(r)*/
|
||||
static int gpu_control_reg_snapshot[] = {
|
||||
GPU_ID,
|
||||
SHADER_READY_LO,
|
||||
SHADER_READY_HI,
|
||||
TILER_READY_LO,
|
||||
TILER_READY_HI,
|
||||
L2_READY_LO,
|
||||
L2_READY_HI
|
||||
};
|
||||
|
||||
/* JOB_CONTROL_REG(r) */
|
||||
static int job_control_reg_snapshot[] = {
|
||||
JOB_IRQ_MASK,
|
||||
JOB_IRQ_STATUS
|
||||
};
|
||||
|
||||
/* JOB_SLOT_REG(n,r) */
|
||||
static int job_slot_reg_snapshot[] = {
|
||||
JS_HEAD_LO,
|
||||
JS_HEAD_HI,
|
||||
JS_TAIL_LO,
|
||||
JS_TAIL_HI,
|
||||
JS_AFFINITY_LO,
|
||||
JS_AFFINITY_HI,
|
||||
JS_CONFIG,
|
||||
JS_STATUS,
|
||||
JS_HEAD_NEXT_LO,
|
||||
JS_HEAD_NEXT_HI,
|
||||
JS_AFFINITY_NEXT_LO,
|
||||
JS_AFFINITY_NEXT_HI,
|
||||
JS_CONFIG_NEXT
|
||||
};
|
||||
|
||||
/*MMU_REG(r)*/
|
||||
static int mmu_reg_snapshot[] = {
|
||||
MMU_IRQ_MASK,
|
||||
MMU_IRQ_STATUS
|
||||
};
|
||||
|
||||
/* MMU_AS_REG(n,r) */
|
||||
static int as_reg_snapshot[] = {
|
||||
AS_TRANSTAB_LO,
|
||||
AS_TRANSTAB_HI,
|
||||
AS_MEMATTR_LO,
|
||||
AS_MEMATTR_HI,
|
||||
AS_FAULTSTATUS,
|
||||
AS_FAULTADDRESS_LO,
|
||||
AS_FAULTADDRESS_HI,
|
||||
AS_STATUS
|
||||
};
|
||||
|
||||
bool kbase_debug_job_fault_reg_snapshot_init(struct kbase_context *kctx,
|
||||
int reg_range)
|
||||
{
|
||||
int i, j;
|
||||
int offset = 0;
|
||||
int slot_number;
|
||||
int as_number;
|
||||
|
||||
if (kctx->reg_dump == NULL)
|
||||
return false;
|
||||
|
||||
slot_number = kctx->kbdev->gpu_props.num_job_slots;
|
||||
as_number = kctx->kbdev->gpu_props.num_address_spaces;
|
||||
|
||||
/* get the GPU control registers*/
|
||||
for (i = 0; i < sizeof(gpu_control_reg_snapshot)/4; i++) {
|
||||
kctx->reg_dump[offset] =
|
||||
GPU_CONTROL_REG(gpu_control_reg_snapshot[i]);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
/* get the Job control registers*/
|
||||
for (i = 0; i < sizeof(job_control_reg_snapshot)/4; i++) {
|
||||
kctx->reg_dump[offset] =
|
||||
JOB_CONTROL_REG(job_control_reg_snapshot[i]);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
/* get the Job Slot registers*/
|
||||
for (j = 0; j < slot_number; j++) {
|
||||
for (i = 0; i < sizeof(job_slot_reg_snapshot)/4; i++) {
|
||||
kctx->reg_dump[offset] =
|
||||
JOB_SLOT_REG(j, job_slot_reg_snapshot[i]);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the MMU registers*/
|
||||
for (i = 0; i < sizeof(mmu_reg_snapshot)/4; i++) {
|
||||
kctx->reg_dump[offset] = MMU_REG(mmu_reg_snapshot[i]);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
/* get the Address space registers*/
|
||||
for (j = 0; j < as_number; j++) {
|
||||
for (i = 0; i < sizeof(as_reg_snapshot)/4; i++) {
|
||||
kctx->reg_dump[offset] =
|
||||
MMU_AS_REG(j, as_reg_snapshot[i]);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
WARN_ON(offset >= (reg_range*2/4));
|
||||
|
||||
/* set the termination flag*/
|
||||
kctx->reg_dump[offset] = REGISTER_DUMP_TERMINATION_FLAG;
|
||||
kctx->reg_dump[offset + 1] = REGISTER_DUMP_TERMINATION_FLAG;
|
||||
|
||||
dev_dbg(kctx->kbdev->dev, "kbase_job_fault_reg_snapshot_init:%d\n",
|
||||
offset);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool kbase_job_fault_get_reg_snapshot(struct kbase_context *kctx)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
if (kctx->reg_dump == NULL)
|
||||
return false;
|
||||
|
||||
while (kctx->reg_dump[offset] != REGISTER_DUMP_TERMINATION_FLAG) {
|
||||
kctx->reg_dump[offset+1] =
|
||||
kbase_reg_read(kctx->kbdev,
|
||||
kctx->reg_dump[offset], NULL);
|
||||
offset += 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
284
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_devfreq.c
Normal file
284
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_devfreq.c
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/devfreq.h>
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#endif
|
||||
|
||||
#include <linux/version.h>
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
#include <linux/pm_opp.h>
|
||||
#else /* Linux >= 3.13 */
|
||||
/* In 3.13 the OPP include header file, types, and functions were all
|
||||
* renamed. Use the old filename for the include, and define the new names to
|
||||
* the old, when an old kernel is detected.
|
||||
*/
|
||||
#include <linux/opp.h>
|
||||
#define dev_pm_opp opp
|
||||
#define dev_pm_opp_get_voltage opp_get_voltage
|
||||
#define dev_pm_opp_get_opp_count opp_get_opp_count
|
||||
#define dev_pm_opp_find_freq_ceil opp_find_freq_ceil
|
||||
#endif /* Linux >= 3.13 */
|
||||
|
||||
|
||||
static int
|
||||
kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
struct dev_pm_opp *opp;
|
||||
unsigned long freq = 0;
|
||||
unsigned long voltage;
|
||||
int err;
|
||||
|
||||
freq = *target_freq;
|
||||
|
||||
rcu_read_lock();
|
||||
opp = devfreq_recommended_opp(dev, &freq, flags);
|
||||
voltage = dev_pm_opp_get_voltage(opp);
|
||||
rcu_read_unlock();
|
||||
if (IS_ERR_OR_NULL(opp)) {
|
||||
dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp));
|
||||
return PTR_ERR(opp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Only update if there is a change of frequency
|
||||
*/
|
||||
if (kbdev->current_freq == freq) {
|
||||
*target_freq = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
if (kbdev->regulator && kbdev->current_voltage != voltage
|
||||
&& kbdev->current_freq < freq) {
|
||||
err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to increase voltage (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = clk_set_rate(kbdev->clock, freq);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to set clock %lu (target %lu)\n",
|
||||
freq, *target_freq);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
if (kbdev->regulator && kbdev->current_voltage != voltage
|
||||
&& kbdev->current_freq > freq) {
|
||||
err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to decrease voltage (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
*target_freq = freq;
|
||||
kbdev->current_voltage = voltage;
|
||||
kbdev->current_freq = freq;
|
||||
|
||||
kbase_pm_reset_dvfs_utilisation(kbdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
kbase_devfreq_cur_freq(struct device *dev, unsigned long *freq)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
|
||||
*freq = kbdev->current_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
kbase_devfreq_status(struct device *dev, struct devfreq_dev_status *stat)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
|
||||
stat->current_frequency = kbdev->current_freq;
|
||||
|
||||
kbase_pm_get_dvfs_utilisation(kbdev,
|
||||
&stat->total_time, &stat->busy_time);
|
||||
|
||||
stat->private_data = NULL;
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
memcpy(&kbdev->devfreq_cooling->last_status, stat, sizeof(*stat));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev,
|
||||
struct devfreq_dev_profile *dp)
|
||||
{
|
||||
int count;
|
||||
int i = 0;
|
||||
unsigned long freq = 0;
|
||||
struct dev_pm_opp *opp;
|
||||
|
||||
rcu_read_lock();
|
||||
count = dev_pm_opp_get_opp_count(kbdev->dev);
|
||||
if (count < 0) {
|
||||
rcu_read_unlock();
|
||||
return count;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]),
|
||||
GFP_KERNEL);
|
||||
if (!dp->freq_table)
|
||||
return -ENOMEM;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < count; i++, freq++) {
|
||||
opp = dev_pm_opp_find_freq_ceil(kbdev->dev, &freq);
|
||||
if (IS_ERR(opp))
|
||||
break;
|
||||
|
||||
dp->freq_table[i] = freq;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (count != i)
|
||||
dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n",
|
||||
count, i);
|
||||
|
||||
dp->max_state = i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbase_devfreq_term_freq_table(struct kbase_device *kbdev)
|
||||
{
|
||||
struct devfreq_dev_profile *dp = kbdev->devfreq->profile;
|
||||
|
||||
kfree(dp->freq_table);
|
||||
}
|
||||
|
||||
static void kbase_devfreq_exit(struct device *dev)
|
||||
{
|
||||
struct kbase_device *kbdev = dev_get_drvdata(dev);
|
||||
|
||||
kbase_devfreq_term_freq_table(kbdev);
|
||||
}
|
||||
|
||||
int kbase_devfreq_init(struct kbase_device *kbdev)
|
||||
{
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
struct devfreq_cooling_ops *callbacks = POWER_MODEL_CALLBACKS;
|
||||
#endif
|
||||
struct devfreq_dev_profile *dp;
|
||||
int err;
|
||||
|
||||
dev_dbg(kbdev->dev, "Init Mali devfreq\n");
|
||||
|
||||
if (!kbdev->clock)
|
||||
return -ENODEV;
|
||||
|
||||
kbdev->current_freq = clk_get_rate(kbdev->clock);
|
||||
|
||||
dp = &kbdev->devfreq_profile;
|
||||
|
||||
dp->initial_freq = kbdev->current_freq;
|
||||
dp->polling_ms = 100;
|
||||
dp->target = kbase_devfreq_target;
|
||||
dp->get_dev_status = kbase_devfreq_status;
|
||||
dp->get_cur_freq = kbase_devfreq_cur_freq;
|
||||
dp->exit = kbase_devfreq_exit;
|
||||
|
||||
if (kbase_devfreq_init_freq_table(kbdev, dp))
|
||||
return -EFAULT;
|
||||
|
||||
kbdev->devfreq = devfreq_add_device(kbdev->dev, dp,
|
||||
"simple_ondemand", NULL);
|
||||
if (IS_ERR(kbdev->devfreq)) {
|
||||
kbase_devfreq_term_freq_table(kbdev);
|
||||
return PTR_ERR(kbdev->devfreq);
|
||||
}
|
||||
|
||||
err = devfreq_register_opp_notifier(kbdev->dev, kbdev->devfreq);
|
||||
if (err) {
|
||||
dev_err(kbdev->dev,
|
||||
"Failed to register OPP notifier (%d)\n", err);
|
||||
goto opp_notifier_failed;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
if (callbacks) {
|
||||
|
||||
kbdev->devfreq_cooling = of_devfreq_cooling_register_power(
|
||||
kbdev->dev->of_node,
|
||||
kbdev->devfreq,
|
||||
callbacks);
|
||||
if (IS_ERR_OR_NULL(kbdev->devfreq_cooling)) {
|
||||
err = PTR_ERR(kbdev->devfreq_cooling);
|
||||
dev_err(kbdev->dev,
|
||||
"Failed to register cooling device (%d)\n",
|
||||
err);
|
||||
goto cooling_failed;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
cooling_failed:
|
||||
devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq);
|
||||
#endif /* CONFIG_DEVFREQ_THERMAL */
|
||||
opp_notifier_failed:
|
||||
err = devfreq_remove_device(kbdev->devfreq);
|
||||
if (err)
|
||||
dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err);
|
||||
else
|
||||
kbdev->devfreq = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void kbase_devfreq_term(struct kbase_device *kbdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
dev_dbg(kbdev->dev, "Term Mali devfreq\n");
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||
devfreq_cooling_unregister(kbdev->devfreq_cooling);
|
||||
#endif
|
||||
|
||||
devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq);
|
||||
|
||||
err = devfreq_remove_device(kbdev->devfreq);
|
||||
if (err)
|
||||
dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err);
|
||||
else
|
||||
kbdev->devfreq = NULL;
|
||||
}
|
||||
24
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_devfreq.h
Normal file
24
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_devfreq.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _BASE_DEVFREQ_H_
|
||||
#define _BASE_DEVFREQ_H_
|
||||
|
||||
int kbase_devfreq_init(struct kbase_device *kbdev);
|
||||
void kbase_devfreq_term(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _BASE_DEVFREQ_H_ */
|
||||
116
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_device_hw.c
Normal file
116
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_device_hw.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <backend/gpu/mali_kbase_instr_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
|
||||
#if !defined(CONFIG_MALI_NO_MALI)
|
||||
void kbase_reg_write(struct kbase_device *kbdev, u16 offset, u32 value,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
|
||||
KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
|
||||
KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
|
||||
dev_dbg(kbdev->dev, "w: reg %04x val %08x", offset, value);
|
||||
writel(value, kbdev->reg + offset);
|
||||
if (kctx && kctx->jctx.tb)
|
||||
kbase_device_trace_register_access(kctx, REG_WRITE, offset,
|
||||
value);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_reg_write);
|
||||
|
||||
u32 kbase_reg_read(struct kbase_device *kbdev, u16 offset,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
u32 val;
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
|
||||
KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
|
||||
KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
|
||||
val = readl(kbdev->reg + offset);
|
||||
dev_dbg(kbdev->dev, "r: reg %04x val %08x", offset, val);
|
||||
if (kctx && kctx->jctx.tb)
|
||||
kbase_device_trace_register_access(kctx, REG_READ, offset, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_reg_read);
|
||||
#endif /* !defined(CONFIG_MALI_NO_MALI) */
|
||||
|
||||
/**
|
||||
* kbase_report_gpu_fault - Report a GPU fault.
|
||||
* @kbdev: Kbase device pointer
|
||||
* @multiple: Zero if only GPU_FAULT was raised, non-zero if MULTIPLE_GPU_FAULTS
|
||||
* was also set
|
||||
*
|
||||
* This function is called from the interrupt handler when a GPU fault occurs.
|
||||
* It reports the details of the fault using dev_warn().
|
||||
*/
|
||||
static void kbase_report_gpu_fault(struct kbase_device *kbdev, int multiple)
|
||||
{
|
||||
u32 status;
|
||||
u64 address;
|
||||
|
||||
status = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTSTATUS), NULL);
|
||||
address = (u64) kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(GPU_FAULTADDRESS_HI), NULL) << 32;
|
||||
address |= kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(GPU_FAULTADDRESS_LO), NULL);
|
||||
|
||||
dev_warn(kbdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx",
|
||||
status & 0xFF,
|
||||
kbase_exception_name(kbdev, status),
|
||||
address);
|
||||
if (multiple)
|
||||
dev_warn(kbdev->dev, "There were multiple GPU faults - some have not been reported\n");
|
||||
}
|
||||
|
||||
void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val)
|
||||
{
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ, NULL, NULL, 0u, val);
|
||||
if (val & GPU_FAULT)
|
||||
kbase_report_gpu_fault(kbdev, val & MULTIPLE_GPU_FAULTS);
|
||||
|
||||
if (val & RESET_COMPLETED)
|
||||
kbase_pm_reset_done(kbdev);
|
||||
|
||||
if (val & PRFCNT_SAMPLE_COMPLETED)
|
||||
kbase_instr_hwcnt_sample_done(kbdev);
|
||||
|
||||
if (val & CLEAN_CACHES_COMPLETED)
|
||||
kbase_clean_caches_done(kbdev);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, NULL, 0u, val);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), val, NULL);
|
||||
|
||||
/* kbase_pm_check_transitions must be called after the IRQ has been
|
||||
* cleared. This is because it might trigger further power transitions
|
||||
* and we don't want to miss the interrupt raised to notify us that
|
||||
* these further transitions have finished.
|
||||
*/
|
||||
if (val & POWER_CHANGED_ALL)
|
||||
kbase_pm_power_changed(kbdev);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_DONE, NULL, NULL, 0u, val);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend-specific HW access device APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_DEVICE_INTERNAL_H_
|
||||
#define _KBASE_DEVICE_INTERNAL_H_
|
||||
|
||||
/**
|
||||
* kbase_reg_write - write to GPU register
|
||||
* @kbdev: Kbase device pointer
|
||||
* @offset: Offset of register
|
||||
* @value: Value to write
|
||||
* @kctx: Kbase context pointer. May be NULL
|
||||
*
|
||||
* Caller must ensure the GPU is powered (@kbdev->pm.gpu_powered != false). If
|
||||
* @kctx is not NULL then the caller must ensure it is scheduled (@kctx->as_nr
|
||||
* != KBASEP_AS_NR_INVALID).
|
||||
*/
|
||||
void kbase_reg_write(struct kbase_device *kbdev, u16 offset, u32 value,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_reg_read - read from GPU register
|
||||
* @kbdev: Kbase device pointer
|
||||
* @offset: Offset of register
|
||||
* @kctx: Kbase context pointer. May be NULL
|
||||
*
|
||||
* Caller must ensure the GPU is powered (@kbdev->pm.gpu_powered != false). If
|
||||
* @kctx is not NULL then the caller must ensure it is scheduled (@kctx->as_nr
|
||||
* != KBASEP_AS_NR_INVALID).
|
||||
*
|
||||
* Return: Value in desired register
|
||||
*/
|
||||
u32 kbase_reg_read(struct kbase_device *kbdev, u16 offset,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
|
||||
/**
|
||||
* kbase_gpu_interrupt - GPU interrupt handler
|
||||
* @kbdev: Kbase device pointer
|
||||
* @val: The value of the GPU IRQ status register which triggered the call
|
||||
*
|
||||
* This function is called from the interrupt handler when a GPU irq is to be
|
||||
* handled.
|
||||
*/
|
||||
void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val);
|
||||
|
||||
#endif /* _KBASE_DEVICE_INTERNAL_H_ */
|
||||
125
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_gpu.c
Normal file
125
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_gpu.c
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register-based HW access backend APIs
|
||||
*/
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_hwaccess_jm.h>
|
||||
#include <mali_kbase_hwaccess_backend.h>
|
||||
#include <backend/gpu/mali_kbase_irq_internal.h>
|
||||
#include <backend/gpu/mali_kbase_jm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_js_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
int kbase_backend_early_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = kbasep_platform_device_init(kbdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Ensure we can access the GPU registers */
|
||||
kbase_pm_register_access_enable(kbdev);
|
||||
|
||||
/* Find out GPU properties based on the GPU feature registers */
|
||||
kbase_gpuprops_set(kbdev);
|
||||
|
||||
/* We're done accessing the GPU registers for now. */
|
||||
kbase_pm_register_access_disable(kbdev);
|
||||
|
||||
err = kbase_hwaccess_pm_init(kbdev);
|
||||
if (err)
|
||||
goto fail_pm;
|
||||
|
||||
err = kbase_install_interrupts(kbdev);
|
||||
if (err)
|
||||
goto fail_interrupts;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_interrupts:
|
||||
kbase_hwaccess_pm_term(kbdev);
|
||||
fail_pm:
|
||||
kbasep_platform_device_term(kbdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void kbase_backend_early_term(struct kbase_device *kbdev)
|
||||
{
|
||||
kbase_release_interrupts(kbdev);
|
||||
kbase_hwaccess_pm_term(kbdev);
|
||||
kbasep_platform_device_term(kbdev);
|
||||
}
|
||||
|
||||
int kbase_backend_late_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = kbase_backend_timer_init(kbdev);
|
||||
if (err)
|
||||
goto fail_timer;
|
||||
|
||||
/* MALI_SEC_INTEGRATION - timer_init, powerup switching location for sec_hwcnt */
|
||||
err = kbase_hwaccess_pm_powerup(kbdev, PM_HW_ISSUES_DETECT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Currently disabled on the prototype */
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#ifndef CONFIG_MALI_NO_MALI
|
||||
if (kbasep_common_test_interrupt_handlers(kbdev) != 0) {
|
||||
dev_err(kbdev->dev, "Interrupt assigment check failed.\n");
|
||||
err = -EINVAL;
|
||||
goto fail_interrupt_test;
|
||||
}
|
||||
#endif /* !CONFIG_MALI_NO_MALI */
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
err = kbase_job_slot_init(kbdev);
|
||||
if (err)
|
||||
goto fail_job_slot;
|
||||
|
||||
init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_job_slot:
|
||||
/* Currently disabled on the prototype */
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#ifndef CONFIG_MALI_NO_MALI
|
||||
fail_interrupt_test:
|
||||
#endif /* !CONFIG_MALI_NO_MALI */
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
kbase_backend_timer_term(kbdev);
|
||||
fail_timer:
|
||||
kbase_hwaccess_pm_halt(kbdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void kbase_backend_late_term(struct kbase_device *kbdev)
|
||||
{
|
||||
kbase_job_slot_halt(kbdev);
|
||||
kbase_job_slot_term(kbdev);
|
||||
kbase_backend_timer_term(kbdev);
|
||||
kbase_hwaccess_pm_halt(kbdev);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel property query backend APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
#include <mali_kbase_hwaccess_gpuprops.h>
|
||||
|
||||
void kbase_backend_gpuprops_get(struct kbase_device *kbdev,
|
||||
struct kbase_gpuprops_regdump *regdump)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Fill regdump with the content of the relevant registers */
|
||||
regdump->gpu_id = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID), NULL);
|
||||
|
||||
regdump->l2_features = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(L2_FEATURES), NULL);
|
||||
regdump->suspend_size = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(SUSPEND_SIZE), NULL);
|
||||
regdump->tiler_features = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(TILER_FEATURES), NULL);
|
||||
regdump->mem_features = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(MEM_FEATURES), NULL);
|
||||
regdump->mmu_features = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(MMU_FEATURES), NULL);
|
||||
regdump->as_present = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(AS_PRESENT), NULL);
|
||||
regdump->js_present = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(JS_PRESENT), NULL);
|
||||
|
||||
for (i = 0; i < GPU_MAX_JOB_SLOTS; i++)
|
||||
regdump->js_features[i] = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(JS_FEATURES_REG(i)), NULL);
|
||||
|
||||
for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
|
||||
regdump->texture_features[i] = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(TEXTURE_FEATURES_REG(i)), NULL);
|
||||
|
||||
regdump->thread_max_threads = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(THREAD_MAX_THREADS), NULL);
|
||||
regdump->thread_max_workgroup_size = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(THREAD_MAX_WORKGROUP_SIZE),
|
||||
NULL);
|
||||
regdump->thread_max_barrier_size = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(THREAD_MAX_BARRIER_SIZE), NULL);
|
||||
regdump->thread_features = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(THREAD_FEATURES), NULL);
|
||||
|
||||
regdump->shader_present_lo = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(SHADER_PRESENT_LO), NULL);
|
||||
regdump->shader_present_hi = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(SHADER_PRESENT_HI), NULL);
|
||||
|
||||
regdump->tiler_present_lo = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(TILER_PRESENT_LO), NULL);
|
||||
regdump->tiler_present_hi = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(TILER_PRESENT_HI), NULL);
|
||||
|
||||
regdump->l2_present_lo = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(L2_PRESENT_LO), NULL);
|
||||
regdump->l2_present_hi = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(L2_PRESENT_HI), NULL);
|
||||
}
|
||||
|
||||
637
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_instr_backend.c
Normal file
637
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_instr_backend.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GPU backend instrumentation APIs.
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_instr_internal.h>
|
||||
|
||||
/**
|
||||
* kbasep_instr_hwcnt_cacheclean - Issue Cache Clean & Invalidate command to
|
||||
* hardware
|
||||
*
|
||||
* @kbdev: Kbase device
|
||||
*/
|
||||
static void kbasep_instr_hwcnt_cacheclean(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long pm_flags;
|
||||
u32 irq_mask;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
/* Wait for any reset to complete */
|
||||
while (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING) {
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach) {
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.cache_clean_wait,
|
||||
kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_RESETTING, kbdev->hwcnt.timeout);
|
||||
if (ret == 0)
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.cache_clean_wait,
|
||||
kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_RESETTING);
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state ==
|
||||
KBASE_INSTR_STATE_REQUEST_CLEAN);
|
||||
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
/* consider hwcnt state before register access */
|
||||
if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_REQUEST_CLEAN) {
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable interrupt */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, pm_flags);
|
||||
irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
|
||||
irq_mask | CLEAN_CACHES_COMPLETED, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, pm_flags);
|
||||
|
||||
/* clean&invalidate the caches so we're sure the mmu tables for the dump
|
||||
* buffer is valid */
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, NULL, 0u, 0);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
|
||||
GPU_COMMAND_CLEAN_INV_CACHES, NULL);
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_CLEANING;
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
struct kbase_uk_hwcnt_setup *setup)
|
||||
{
|
||||
unsigned long flags, pm_flags;
|
||||
int err = -EINVAL;
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
u32 irq_mask;
|
||||
int ret;
|
||||
u64 shader_cores_needed;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL == kbdev->hwcnt.suspended_kctx);
|
||||
|
||||
shader_cores_needed = kbase_pm_get_present_cores(kbdev,
|
||||
KBASE_PM_CORE_SHADER);
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
/* alignment failure */
|
||||
if ((setup->dump_buffer == 0ULL) || (setup->dump_buffer & (2048 - 1)))
|
||||
goto out_err;
|
||||
|
||||
/* Override core availability policy to ensure all cores are available
|
||||
*/
|
||||
kbase_pm_ca_instr_enable(kbdev);
|
||||
|
||||
/* Request the cores early on synchronously - we'll release them on any
|
||||
* errors (e.g. instrumentation already active) */
|
||||
#ifndef MALI_SEC_HWCNT
|
||||
kbase_pm_request_cores_sync(kbdev, true, shader_cores_needed);
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING) {
|
||||
/* GPU is being reset */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
{
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.wait, kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
if (ret == 0) {
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
err = -EINVAL;
|
||||
GPU_LOG(DVFS_WARNING, DUMMY, 0u, 0u, "skip enable hwcnt %d \n", __LINE__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
#endif
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_DISABLED) {
|
||||
/* Instrumentation is already enabled */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
goto out_unrequest_cores;
|
||||
}
|
||||
|
||||
/* Enable interrupt */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, pm_flags);
|
||||
irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), irq_mask |
|
||||
PRFCNT_SAMPLE_COMPLETED, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, pm_flags);
|
||||
|
||||
/* In use, this context is the owner */
|
||||
kbdev->hwcnt.kctx = kctx;
|
||||
/* Remember the dump address so we can reprogram it later */
|
||||
kbdev->hwcnt.addr = setup->dump_buffer;
|
||||
/* Remember all the settings for suspend/resume */
|
||||
if (&kbdev->hwcnt.suspended_state != setup)
|
||||
memcpy(&kbdev->hwcnt.suspended_state, setup,
|
||||
sizeof(kbdev->hwcnt.suspended_state));
|
||||
|
||||
/* Request the clean */
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_REQUEST_CLEAN;
|
||||
kbdev->hwcnt.backend.triggered = 0;
|
||||
/* Clean&invalidate the caches so we're sure the mmu tables for the dump
|
||||
* buffer is valid */
|
||||
ret = queue_work(kbdev->hwcnt.backend.cache_clean_wq,
|
||||
&kbdev->hwcnt.backend.cache_clean_work);
|
||||
KBASE_DEBUG_ASSERT(ret);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
{
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.wait, kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
if (ret == 0) {
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
err = -EINVAL;
|
||||
GPU_LOG(DVFS_WARNING, DUMMY, 0u, 0u, "skip enable hwcnt %d \n", __LINE__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Wait for cacheclean to complete */
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
#endif
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state ==
|
||||
KBASE_INSTR_STATE_IDLE);
|
||||
|
||||
kbase_pm_request_l2_caches(kbdev);
|
||||
|
||||
/* Configure */
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG),
|
||||
(kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT)
|
||||
| PRFCNT_CONFIG_MODE_OFF, kctx);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO),
|
||||
setup->dump_buffer & 0xFFFFFFFF, kctx);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI),
|
||||
setup->dump_buffer >> 32, kctx);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN),
|
||||
setup->jm_bm, kctx);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN),
|
||||
setup->shader_bm, kctx);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN),
|
||||
setup->mmu_l2_bm, kctx);
|
||||
/* Due to PRLAM-8186 we need to disable the Tiler before we enable the
|
||||
* HW counter dump. */
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186))
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN), 0,
|
||||
kctx);
|
||||
else
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN),
|
||||
setup->tiler_bm, kctx);
|
||||
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG),
|
||||
(kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT) |
|
||||
PRFCNT_CONFIG_MODE_MANUAL, kctx);
|
||||
|
||||
/* If HW has PRLAM-8186 we can now re-enable the tiler HW counters dump
|
||||
*/
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8186))
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN),
|
||||
setup->tiler_bm, kctx);
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING) {
|
||||
/* GPU is being reset */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
{
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.wait, kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
if (ret == 0) {
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
err = -EINVAL;
|
||||
GPU_LOG(DVFS_WARNING, DUMMY, 0u, 0u, "skip enable hwcnt %d \n", __LINE__);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
#else
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
#endif
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
kbdev->hwcnt.backend.triggered = 1;
|
||||
wake_up(&kbdev->hwcnt.backend.wait);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
err = 0;
|
||||
|
||||
dev_dbg(kbdev->dev, "HW counters dumping set-up for context %p", kctx);
|
||||
return err;
|
||||
out_unrequest_cores:
|
||||
kbase_pm_unrequest_cores(kbdev, true, shader_cores_needed);
|
||||
out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_disable_internal(struct kbase_context *kctx)
|
||||
{
|
||||
unsigned long flags, pm_flags;
|
||||
int err = -EINVAL;
|
||||
u32 irq_mask;
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
|
||||
while (1) {
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_DISABLED) {
|
||||
/* Instrumentation is not enabled */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kbdev->hwcnt.kctx != kctx) {
|
||||
/* Instrumentation has been setup for another context */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_IDLE)
|
||||
break;
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
/* Ongoing dump/setup - wait for its completion */
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach) {
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
if (ret == 0)
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
}
|
||||
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DISABLED;
|
||||
kbdev->hwcnt.backend.triggered = 0;
|
||||
|
||||
/* Disable interrupt */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, pm_flags);
|
||||
irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), NULL);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
|
||||
irq_mask & ~PRFCNT_SAMPLE_COMPLETED, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, pm_flags);
|
||||
|
||||
/* Disable the counters */
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG), 0, kctx);
|
||||
|
||||
kbdev->hwcnt.kctx = NULL;
|
||||
kbdev->hwcnt.addr = 0ULL;
|
||||
|
||||
kbase_pm_ca_instr_disable(kbdev);
|
||||
|
||||
#ifndef MALI_SEC_HWCNT
|
||||
kbase_pm_unrequest_cores(kbdev, true,
|
||||
kbase_pm_get_present_cores(kbdev, KBASE_PM_CORE_SHADER));
|
||||
#endif
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
kbase_pm_release_l2_caches(kbdev);
|
||||
|
||||
dev_dbg(kbdev->dev, "HW counters dumping disabled for context %p",
|
||||
kctx);
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = -EINVAL;
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.kctx != kctx) {
|
||||
/* The instrumentation has been setup for another context */
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_IDLE) {
|
||||
/* HW counters are disabled or another dump is ongoing, or we're
|
||||
* resetting */
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
kbdev->hwcnt.backend.triggered = 0;
|
||||
|
||||
/* Mark that we're dumping - the PF handler can signal that we faulted
|
||||
*/
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DUMPING;
|
||||
|
||||
/* Reconfigure the dump address */
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_LO),
|
||||
kbdev->hwcnt.addr & 0xFFFFFFFF, NULL);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI),
|
||||
kbdev->hwcnt.addr >> 32, NULL);
|
||||
|
||||
/* Start dumping */
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_SAMPLE, NULL, NULL,
|
||||
kbdev->hwcnt.addr, 0);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
|
||||
GPU_COMMAND_PRFCNT_SAMPLE, kctx);
|
||||
|
||||
dev_dbg(kbdev->dev, "HW counters dumping done for context %p", kctx);
|
||||
|
||||
err = 0;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_request_dump);
|
||||
|
||||
bool kbase_instr_hwcnt_dump_complete(struct kbase_context *kctx,
|
||||
bool * const success)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool complete = false;
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_IDLE) {
|
||||
*success = true;
|
||||
complete = true;
|
||||
} else if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) {
|
||||
*success = false;
|
||||
complete = true;
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
return complete;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump_complete);
|
||||
|
||||
void kbasep_cache_clean_worker(struct work_struct *data)
|
||||
{
|
||||
struct kbase_device *kbdev;
|
||||
unsigned long flags;
|
||||
|
||||
kbdev = container_of(data, struct kbase_device,
|
||||
hwcnt.backend.cache_clean_work);
|
||||
|
||||
mutex_lock(&kbdev->cacheclean_lock);
|
||||
kbasep_instr_hwcnt_cacheclean(kbdev);
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
/* Wait for our condition, and any reset to complete */
|
||||
while (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING ||
|
||||
kbdev->hwcnt.backend.state ==
|
||||
KBASE_INSTR_STATE_CLEANING) {
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach) {
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.cache_clean_wait,
|
||||
(kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_RESETTING &&
|
||||
kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_CLEANING), kbdev->hwcnt.timeout);
|
||||
if (ret == 0)
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.cache_clean_wait,
|
||||
(kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_RESETTING &&
|
||||
kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_CLEANING));
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state ==
|
||||
KBASE_INSTR_STATE_CLEANED);
|
||||
|
||||
/* All finished and idle */
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
kbdev->hwcnt.backend.triggered = 1;
|
||||
wake_up(&kbdev->hwcnt.backend.wait);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
mutex_unlock(&kbdev->cacheclean_lock);
|
||||
}
|
||||
|
||||
void kbase_instr_hwcnt_sample_done(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) {
|
||||
kbdev->hwcnt.backend.triggered = 1;
|
||||
wake_up(&kbdev->hwcnt.backend.wait);
|
||||
} else if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_DUMPING) {
|
||||
int ret;
|
||||
/* Always clean and invalidate the cache after a successful dump
|
||||
*/
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_REQUEST_CLEAN;
|
||||
ret = queue_work(kbdev->hwcnt.backend.cache_clean_wq,
|
||||
&kbdev->hwcnt.backend.cache_clean_work);
|
||||
KBASE_DEBUG_ASSERT(ret);
|
||||
}
|
||||
/* NOTE: In the state KBASE_INSTR_STATE_RESETTING, We're in a reset,
|
||||
* and the instrumentation state hasn't been restored yet -
|
||||
* kbasep_reset_timeout_worker() will do the rest of the work */
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
void kbase_clean_caches_done(struct kbase_device *kbdev)
|
||||
{
|
||||
u32 irq_mask;
|
||||
|
||||
if (kbdev->hwcnt.backend.state != KBASE_INSTR_STATE_DISABLED) {
|
||||
unsigned long flags;
|
||||
unsigned long pm_flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
/* Disable interrupt */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, pm_flags);
|
||||
irq_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
|
||||
NULL);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
|
||||
irq_mask & ~CLEAN_CACHES_COMPLETED, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, pm_flags);
|
||||
|
||||
/* Wakeup... */
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_CLEANING) {
|
||||
/* Only wake if we weren't resetting */
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_CLEANED;
|
||||
wake_up(&kbdev->hwcnt.backend.cache_clean_wait);
|
||||
}
|
||||
/* NOTE: In the state KBASE_INSTR_STATE_RESETTING, We're in a
|
||||
* reset, and the instrumentation state hasn't been restored yet
|
||||
* - kbasep_reset_timeout_worker() will do the rest of the work
|
||||
*/
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_wait_for_dump(struct kbase_context *kctx)
|
||||
{
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
/* Wait for dump & cacheclean to complete */
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach) {
|
||||
int ret = wait_event_timeout(kbdev->hwcnt.backend.wait, kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
if (ret == 0) {
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
err = -EINVAL;
|
||||
GPU_LOG(DVFS_WARNING, DUMMY, 0u, 0u, "skip dump hwcnt %d \n", __LINE__);
|
||||
return err;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING) {
|
||||
/* GPU is being reset */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach)
|
||||
wait_event_timeout(kbdev->hwcnt.backend.wait, kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_FAULT) {
|
||||
err = -EINVAL;
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_IDLE;
|
||||
} else {
|
||||
/* Dump done */
|
||||
KBASE_DEBUG_ASSERT(kbdev->hwcnt.backend.state ==
|
||||
KBASE_INSTR_STATE_IDLE);
|
||||
err = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_clear(struct kbase_context *kctx)
|
||||
{
|
||||
unsigned long flags;
|
||||
int err = -EINVAL;
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
|
||||
if (kbdev->hwcnt.backend.state == KBASE_INSTR_STATE_RESETTING) {
|
||||
/* GPU is being reset */
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach)
|
||||
wait_event_timeout(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0, kbdev->hwcnt.timeout);
|
||||
else
|
||||
#endif
|
||||
wait_event(kbdev->hwcnt.backend.wait,
|
||||
kbdev->hwcnt.backend.triggered != 0);
|
||||
spin_lock_irqsave(&kbdev->hwcnt.lock, flags);
|
||||
}
|
||||
|
||||
/* Check it's the context previously set up and we're not already
|
||||
* dumping */
|
||||
if (kbdev->hwcnt.kctx != kctx || kbdev->hwcnt.backend.state !=
|
||||
KBASE_INSTR_STATE_IDLE)
|
||||
goto out;
|
||||
|
||||
/* Clear the counters */
|
||||
KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_CLEAR, NULL, NULL, 0u, 0);
|
||||
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
|
||||
GPU_COMMAND_PRFCNT_CLEAR, kctx);
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_clear);
|
||||
|
||||
int kbase_instr_backend_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
kbdev->hwcnt.backend.state = KBASE_INSTR_STATE_DISABLED;
|
||||
|
||||
init_waitqueue_head(&kbdev->hwcnt.backend.wait);
|
||||
init_waitqueue_head(&kbdev->hwcnt.backend.cache_clean_wait);
|
||||
INIT_WORK(&kbdev->hwcnt.backend.cache_clean_work,
|
||||
kbasep_cache_clean_worker);
|
||||
kbdev->hwcnt.backend.triggered = 0;
|
||||
|
||||
kbdev->hwcnt.backend.cache_clean_wq =
|
||||
alloc_workqueue("Mali cache cleaning workqueue", 0, 1);
|
||||
if (NULL == kbdev->hwcnt.backend.cache_clean_wq)
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kbase_instr_backend_term(struct kbase_device *kbdev)
|
||||
{
|
||||
destroy_workqueue(kbdev->hwcnt.backend.cache_clean_wq);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend-specific instrumentation definitions
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_INSTR_DEFS_H_
|
||||
#define _KBASE_INSTR_DEFS_H_
|
||||
|
||||
/*
|
||||
* Instrumentation State Machine States
|
||||
*/
|
||||
enum kbase_instr_state {
|
||||
/* State where instrumentation is not active */
|
||||
KBASE_INSTR_STATE_DISABLED = 0,
|
||||
/* State machine is active and ready for a command. */
|
||||
KBASE_INSTR_STATE_IDLE,
|
||||
/* Hardware is currently dumping a frame. */
|
||||
KBASE_INSTR_STATE_DUMPING,
|
||||
/* We've requested a clean to occur on a workqueue */
|
||||
KBASE_INSTR_STATE_REQUEST_CLEAN,
|
||||
/* Hardware is currently cleaning and invalidating caches. */
|
||||
KBASE_INSTR_STATE_CLEANING,
|
||||
/* Cache clean completed, and either a) a dump is complete, or
|
||||
* b) instrumentation can now be setup. */
|
||||
KBASE_INSTR_STATE_CLEANED,
|
||||
/* kbasep_reset_timeout_worker() has started (but not compelted) a
|
||||
* reset. This generally indicates the current action should be aborted,
|
||||
* and kbasep_reset_timeout_worker() will handle the cleanup */
|
||||
KBASE_INSTR_STATE_RESETTING,
|
||||
/* An error has occured during DUMPING (page fault). */
|
||||
KBASE_INSTR_STATE_FAULT
|
||||
};
|
||||
|
||||
/* Structure used for instrumentation and HW counters dumping */
|
||||
struct kbase_instr_backend {
|
||||
wait_queue_head_t wait;
|
||||
int triggered;
|
||||
|
||||
enum kbase_instr_state state;
|
||||
wait_queue_head_t cache_clean_wait;
|
||||
struct workqueue_struct *cache_clean_wq;
|
||||
struct work_struct cache_clean_work;
|
||||
};
|
||||
|
||||
#endif /* _KBASE_INSTR_DEFS_H_ */
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend-specific HW access instrumentation APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_INSTR_INTERNAL_H_
|
||||
#define _KBASE_INSTR_INTERNAL_H_
|
||||
|
||||
/**
|
||||
* kbasep_cache_clean_worker() - Workqueue for handling cache cleaning
|
||||
* @data: a &struct work_struct
|
||||
*/
|
||||
void kbasep_cache_clean_worker(struct work_struct *data);
|
||||
|
||||
/**
|
||||
* kbase_clean_caches_done() - Cache clean interrupt received
|
||||
* @kbdev: Kbase device
|
||||
*/
|
||||
void kbase_clean_caches_done(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_sample_done() - Dump complete interrupt received
|
||||
* @kbdev: Kbase device
|
||||
*/
|
||||
void kbase_instr_hwcnt_sample_done(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_INSTR_INTERNAL_H_ */
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend specific IRQ APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_IRQ_INTERNAL_H_
|
||||
#define _KBASE_IRQ_INTERNAL_H_
|
||||
|
||||
int kbase_install_interrupts(struct kbase_device *kbdev);
|
||||
|
||||
void kbase_release_interrupts(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_synchronize_irqs - Ensure that all IRQ handlers have completed
|
||||
* execution
|
||||
* @kbdev: The kbase device
|
||||
*/
|
||||
void kbase_synchronize_irqs(struct kbase_device *kbdev);
|
||||
|
||||
int kbasep_common_test_interrupt_handlers(
|
||||
struct kbase_device * const kbdev);
|
||||
|
||||
#endif /* _KBASE_IRQ_INTERNAL_H_ */
|
||||
471
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_irq_linux.c
Normal file
471
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_irq_linux.c
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
#include <backend/gpu/mali_kbase_irq_internal.h>
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#if !defined(CONFIG_MALI_NO_MALI)
|
||||
|
||||
/* GPU IRQ Tags */
|
||||
#define JOB_IRQ_TAG 0
|
||||
#define MMU_IRQ_TAG 1
|
||||
#define GPU_IRQ_TAG 2
|
||||
|
||||
|
||||
static void *kbase_tag(void *ptr, u32 tag)
|
||||
{
|
||||
return (void *)(((uintptr_t) ptr) | tag);
|
||||
}
|
||||
|
||||
static void *kbase_untag(void *ptr)
|
||||
{
|
||||
return (void *)(((uintptr_t) ptr) & ~3);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static irqreturn_t kbase_job_irq_handler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev = kbase_untag(data);
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!kbdev->pm.backend.gpu_powered) {
|
||||
/* GPU is turned off - IRQ is not for us */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
|
||||
flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL);
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
if (!kbdev->pm.backend.driver_ready_for_irqs)
|
||||
dev_warn(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n",
|
||||
__func__, irq, val);
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!val)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
|
||||
|
||||
kbase_job_done(kbdev, val);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_job_irq_handler);
|
||||
|
||||
static irqreturn_t kbase_mmu_irq_handler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev = kbase_untag(data);
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!kbdev->pm.backend.gpu_powered) {
|
||||
/* GPU is turned off - IRQ is not for us */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
|
||||
flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
atomic_inc(&kbdev->faults_pending);
|
||||
|
||||
val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL);
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
if (!kbdev->pm.backend.driver_ready_for_irqs)
|
||||
dev_warn(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n",
|
||||
__func__, irq, val);
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!val) {
|
||||
atomic_dec(&kbdev->faults_pending);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
|
||||
|
||||
kbase_mmu_interrupt(kbdev, val);
|
||||
|
||||
atomic_dec(&kbdev->faults_pending);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t kbase_gpu_irq_handler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev = kbase_untag(data);
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!kbdev->pm.backend.gpu_powered) {
|
||||
/* GPU is turned off - IRQ is not for us */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
|
||||
flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
val = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_STATUS), NULL);
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
if (!kbdev->pm.backend.driver_ready_for_irqs)
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x before driver is ready\n",
|
||||
__func__, irq, val);
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!val)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
|
||||
|
||||
kbase_gpu_interrupt(kbdev, val);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
static irq_handler_t kbase_handler_table[] = {
|
||||
[JOB_IRQ_TAG] = kbase_job_irq_handler,
|
||||
[MMU_IRQ_TAG] = kbase_mmu_irq_handler,
|
||||
[GPU_IRQ_TAG] = kbase_gpu_irq_handler,
|
||||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#define JOB_IRQ_HANDLER JOB_IRQ_TAG
|
||||
#define MMU_IRQ_HANDLER MMU_IRQ_TAG
|
||||
#define GPU_IRQ_HANDLER GPU_IRQ_TAG
|
||||
|
||||
/**
|
||||
* kbase_set_custom_irq_handler - Set a custom IRQ handler
|
||||
* @kbdev: Device for which the handler is to be registered
|
||||
* @custom_handler: Handler to be registered
|
||||
* @irq_type: Interrupt type
|
||||
*
|
||||
* Registers given interrupt handler for requested interrupt type
|
||||
* In the case where irq handler is not specified, the default handler shall be
|
||||
* registered
|
||||
*
|
||||
* Return: 0 case success, error code otherwise
|
||||
*/
|
||||
int kbase_set_custom_irq_handler(struct kbase_device *kbdev,
|
||||
irq_handler_t custom_handler,
|
||||
int irq_type)
|
||||
{
|
||||
int result = 0;
|
||||
irq_handler_t requested_irq_handler = NULL;
|
||||
|
||||
KBASE_DEBUG_ASSERT((JOB_IRQ_HANDLER <= irq_type) &&
|
||||
(GPU_IRQ_HANDLER >= irq_type));
|
||||
|
||||
/* Release previous handler */
|
||||
if (kbdev->irqs[irq_type].irq)
|
||||
free_irq(kbdev->irqs[irq_type].irq, kbase_tag(kbdev, irq_type));
|
||||
|
||||
requested_irq_handler = (NULL != custom_handler) ? custom_handler :
|
||||
kbase_handler_table[irq_type];
|
||||
|
||||
if (0 != request_irq(kbdev->irqs[irq_type].irq,
|
||||
requested_irq_handler,
|
||||
kbdev->irqs[irq_type].flags | IRQF_SHARED,
|
||||
dev_name(kbdev->dev), kbase_tag(kbdev, irq_type))) {
|
||||
result = -EINVAL;
|
||||
dev_err(kbdev->dev, "Can't request interrupt %d (index %d)\n",
|
||||
kbdev->irqs[irq_type].irq, irq_type);
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
dev_err(kbdev->dev, "You have CONFIG_SPARSE_IRQ support enabled - is the interrupt number correct for this configuration?\n");
|
||||
#endif /* CONFIG_SPARSE_IRQ */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_set_custom_irq_handler);
|
||||
|
||||
/* test correct interrupt assigment and reception by cpu */
|
||||
struct kbasep_irq_test {
|
||||
struct hrtimer timer;
|
||||
wait_queue_head_t wait;
|
||||
int triggered;
|
||||
u32 timeout;
|
||||
};
|
||||
|
||||
static struct kbasep_irq_test kbasep_irq_test_data;
|
||||
|
||||
#define IRQ_TEST_TIMEOUT 500
|
||||
|
||||
static irqreturn_t kbase_job_irq_test_handler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev = kbase_untag(data);
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!kbdev->pm.backend.gpu_powered) {
|
||||
/* GPU is turned off - IRQ is not for us */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
|
||||
flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
val = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_STATUS), NULL);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!val)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
|
||||
|
||||
kbasep_irq_test_data.triggered = 1;
|
||||
wake_up(&kbasep_irq_test_data.wait);
|
||||
|
||||
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), val, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t kbase_mmu_irq_test_handler(int irq, void *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev = kbase_untag(data);
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!kbdev->pm.backend.gpu_powered) {
|
||||
/* GPU is turned off - IRQ is not for us */
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock,
|
||||
flags);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
val = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_STATUS), NULL);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, flags);
|
||||
|
||||
if (!val)
|
||||
return IRQ_NONE;
|
||||
|
||||
dev_dbg(kbdev->dev, "%s: irq %d irqstatus 0x%x\n", __func__, irq, val);
|
||||
|
||||
kbasep_irq_test_data.triggered = 1;
|
||||
wake_up(&kbasep_irq_test_data.wait);
|
||||
|
||||
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), val, NULL);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart kbasep_test_interrupt_timeout(struct hrtimer *timer)
|
||||
{
|
||||
struct kbasep_irq_test *test_data = container_of(timer,
|
||||
struct kbasep_irq_test, timer);
|
||||
|
||||
test_data->timeout = 1;
|
||||
test_data->triggered = 1;
|
||||
wake_up(&test_data->wait);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static int kbasep_common_test_interrupt(
|
||||
struct kbase_device * const kbdev, u32 tag)
|
||||
{
|
||||
int err = 0;
|
||||
irq_handler_t test_handler;
|
||||
|
||||
u32 old_mask_val;
|
||||
u16 mask_offset;
|
||||
u16 rawstat_offset;
|
||||
|
||||
switch (tag) {
|
||||
case JOB_IRQ_TAG:
|
||||
test_handler = kbase_job_irq_test_handler;
|
||||
rawstat_offset = JOB_CONTROL_REG(JOB_IRQ_RAWSTAT);
|
||||
mask_offset = JOB_CONTROL_REG(JOB_IRQ_MASK);
|
||||
break;
|
||||
case MMU_IRQ_TAG:
|
||||
test_handler = kbase_mmu_irq_test_handler;
|
||||
rawstat_offset = MMU_REG(MMU_IRQ_RAWSTAT);
|
||||
mask_offset = MMU_REG(MMU_IRQ_MASK);
|
||||
break;
|
||||
case GPU_IRQ_TAG:
|
||||
/* already tested by pm_driver - bail out */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store old mask */
|
||||
old_mask_val = kbase_reg_read(kbdev, mask_offset, NULL);
|
||||
/* mask interrupts */
|
||||
kbase_reg_write(kbdev, mask_offset, 0x0, NULL);
|
||||
|
||||
if (kbdev->irqs[tag].irq) {
|
||||
/* release original handler and install test handler */
|
||||
if (kbase_set_custom_irq_handler(kbdev, test_handler, tag) != 0) {
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
kbasep_irq_test_data.timeout = 0;
|
||||
hrtimer_init(&kbasep_irq_test_data.timer,
|
||||
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
kbasep_irq_test_data.timer.function =
|
||||
kbasep_test_interrupt_timeout;
|
||||
|
||||
/* trigger interrupt */
|
||||
kbase_reg_write(kbdev, mask_offset, 0x1, NULL);
|
||||
kbase_reg_write(kbdev, rawstat_offset, 0x1, NULL);
|
||||
|
||||
hrtimer_start(&kbasep_irq_test_data.timer,
|
||||
HR_TIMER_DELAY_MSEC(IRQ_TEST_TIMEOUT),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
wait_event(kbasep_irq_test_data.wait,
|
||||
kbasep_irq_test_data.triggered != 0);
|
||||
|
||||
if (kbasep_irq_test_data.timeout != 0) {
|
||||
dev_err(kbdev->dev, "Interrupt %d (index %d) didn't reach CPU.\n",
|
||||
kbdev->irqs[tag].irq, tag);
|
||||
err = -EINVAL;
|
||||
} else {
|
||||
dev_dbg(kbdev->dev, "Interrupt %d (index %d) reached CPU.\n",
|
||||
kbdev->irqs[tag].irq, tag);
|
||||
}
|
||||
|
||||
hrtimer_cancel(&kbasep_irq_test_data.timer);
|
||||
kbasep_irq_test_data.triggered = 0;
|
||||
|
||||
/* mask interrupts */
|
||||
kbase_reg_write(kbdev, mask_offset, 0x0, NULL);
|
||||
|
||||
/* release test handler */
|
||||
free_irq(kbdev->irqs[tag].irq, kbase_tag(kbdev, tag));
|
||||
}
|
||||
|
||||
/* restore original interrupt */
|
||||
if (request_irq(kbdev->irqs[tag].irq, kbase_handler_table[tag],
|
||||
kbdev->irqs[tag].flags | IRQF_SHARED,
|
||||
dev_name(kbdev->dev), kbase_tag(kbdev, tag))) {
|
||||
dev_err(kbdev->dev, "Can't restore original interrupt %d (index %d)\n",
|
||||
kbdev->irqs[tag].irq, tag);
|
||||
err = -EINVAL;
|
||||
}
|
||||
}
|
||||
/* restore old mask */
|
||||
kbase_reg_write(kbdev, mask_offset, old_mask_val, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int kbasep_common_test_interrupt_handlers(
|
||||
struct kbase_device * const kbdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
init_waitqueue_head(&kbasep_irq_test_data.wait);
|
||||
kbasep_irq_test_data.triggered = 0;
|
||||
|
||||
/* A suspend won't happen during startup/insmod */
|
||||
kbase_pm_context_active(kbdev);
|
||||
|
||||
err = kbasep_common_test_interrupt(kbdev, JOB_IRQ_TAG);
|
||||
if (err) {
|
||||
dev_err(kbdev->dev, "Interrupt JOB_IRQ didn't reach CPU. Check interrupt assignments.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = kbasep_common_test_interrupt(kbdev, MMU_IRQ_TAG);
|
||||
if (err) {
|
||||
dev_err(kbdev->dev, "Interrupt MMU_IRQ didn't reach CPU. Check interrupt assignments.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev_dbg(kbdev->dev, "Interrupts are correctly assigned.\n");
|
||||
|
||||
out:
|
||||
kbase_pm_context_idle(kbdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
int kbase_install_interrupts(struct kbase_device *kbdev)
|
||||
{
|
||||
u32 nr = ARRAY_SIZE(kbase_handler_table);
|
||||
int err;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
err = request_irq(kbdev->irqs[i].irq, kbase_handler_table[i],
|
||||
kbdev->irqs[i].flags | IRQF_SHARED,
|
||||
dev_name(kbdev->dev),
|
||||
kbase_tag(kbdev, i));
|
||||
if (err) {
|
||||
dev_err(kbdev->dev, "Can't request interrupt %d (index %d)\n",
|
||||
kbdev->irqs[i].irq, i);
|
||||
#ifdef CONFIG_SPARSE_IRQ
|
||||
dev_err(kbdev->dev, "You have CONFIG_SPARSE_IRQ support enabled - is the interrupt number correct for this configuration?\n");
|
||||
#endif /* CONFIG_SPARSE_IRQ */
|
||||
goto release;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
release:
|
||||
while (i-- > 0)
|
||||
free_irq(kbdev->irqs[i].irq, kbase_tag(kbdev, i));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void kbase_release_interrupts(struct kbase_device *kbdev)
|
||||
{
|
||||
u32 nr = ARRAY_SIZE(kbase_handler_table);
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (kbdev->irqs[i].irq)
|
||||
free_irq(kbdev->irqs[i].irq, kbase_tag(kbdev, i));
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_synchronize_irqs(struct kbase_device *kbdev)
|
||||
{
|
||||
u32 nr = ARRAY_SIZE(kbase_handler_table);
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < nr; i++) {
|
||||
if (kbdev->irqs[i].irq)
|
||||
synchronize_irq(kbdev->irqs[i].irq);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !defined(CONFIG_MALI_NO_MALI) */
|
||||
385
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_as.c
Normal file
385
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_as.c
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register backend context / address space management
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_hwaccess_jm.h>
|
||||
|
||||
/**
|
||||
* assign_and_activate_kctx_addr_space - Assign an AS to a context
|
||||
* @kbdev: Kbase device
|
||||
* @kctx: Kbase context
|
||||
* @current_as: Address Space to assign
|
||||
*
|
||||
* Assign an Address Space (AS) to a context, and add the context to the Policy.
|
||||
*
|
||||
* This includes
|
||||
* setting up the global runpool_irq structure and the context on the AS,
|
||||
* Activating the MMU on the AS,
|
||||
* Allowing jobs to be submitted on the AS.
|
||||
*
|
||||
* Context:
|
||||
* kbasep_js_kctx_info.jsctx_mutex held,
|
||||
* kbasep_js_device_data.runpool_mutex held,
|
||||
* AS transaction mutex held,
|
||||
* Runpool IRQ lock held
|
||||
*/
|
||||
static void assign_and_activate_kctx_addr_space(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
struct kbase_as *current_as)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
struct kbasep_js_per_as_data *js_per_as_data;
|
||||
int as_nr = current_as->number;
|
||||
|
||||
lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
lockdep_assert_held(¤t_as->transaction_mutex);
|
||||
lockdep_assert_held(&js_devdata->runpool_irq.lock);
|
||||
|
||||
js_per_as_data = &js_devdata->runpool_irq.per_as_data[as_nr];
|
||||
|
||||
/* Attribute handling */
|
||||
kbasep_js_ctx_attr_runpool_retain_ctx(kbdev, kctx);
|
||||
|
||||
/* Assign addr space */
|
||||
kctx->as_nr = as_nr;
|
||||
|
||||
/* If the GPU is currently powered, activate this address space on the
|
||||
* MMU */
|
||||
if (kbdev->pm.backend.gpu_powered)
|
||||
kbase_mmu_update(kctx);
|
||||
/* If the GPU was not powered then the MMU will be reprogrammed on the
|
||||
* next pm_context_active() */
|
||||
|
||||
/* Allow it to run jobs */
|
||||
kbasep_js_set_submit_allowed(js_devdata, kctx);
|
||||
|
||||
/* Book-keeping */
|
||||
js_per_as_data->kctx = kctx;
|
||||
js_per_as_data->as_busy_refcount = 0;
|
||||
|
||||
kbase_js_runpool_inc_context_count(kbdev, kctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* release_addr_space - Release an address space
|
||||
* @kbdev: Kbase device
|
||||
* @kctx_as_nr: Address space of context to release
|
||||
* @kctx: Context being released
|
||||
*
|
||||
* Context: kbasep_js_device_data.runpool_mutex must be held
|
||||
*
|
||||
* Release an address space, making it available for being picked again.
|
||||
*/
|
||||
static void release_addr_space(struct kbase_device *kbdev, int kctx_as_nr,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
u16 as_bit = (1u << kctx_as_nr);
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
|
||||
/* The address space must not already be free */
|
||||
KBASE_DEBUG_ASSERT(!(js_devdata->as_free & as_bit));
|
||||
|
||||
js_devdata->as_free |= as_bit;
|
||||
|
||||
kbase_js_runpool_dec_context_count(kbdev, kctx);
|
||||
}
|
||||
|
||||
bool kbase_backend_use_ctx_sched(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (kbdev->hwaccess.active_kctx == kctx) {
|
||||
/* Context is already active */
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < kbdev->nr_hw_address_spaces; i++) {
|
||||
struct kbasep_js_per_as_data *js_per_as_data =
|
||||
&kbdev->js_data.runpool_irq.per_as_data[i];
|
||||
|
||||
if (js_per_as_data->kctx == kctx) {
|
||||
/* Context already has ASID - mark as active */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Context does not have address space assigned */
|
||||
return false;
|
||||
}
|
||||
|
||||
void kbase_backend_release_ctx_irq(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
struct kbasep_js_per_as_data *js_per_as_data;
|
||||
int as_nr = kctx->as_nr;
|
||||
|
||||
if (as_nr == KBASEP_AS_NR_INVALID) {
|
||||
WARN(1, "Attempting to release context without ASID\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lockdep_assert_held(&kbdev->as[as_nr].transaction_mutex);
|
||||
lockdep_assert_held(&kbdev->js_data.runpool_irq.lock);
|
||||
|
||||
js_per_as_data = &kbdev->js_data.runpool_irq.per_as_data[kctx->as_nr];
|
||||
if (js_per_as_data->as_busy_refcount != 0) {
|
||||
WARN(1, "Attempting to release active ASID\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Release context from address space */
|
||||
js_per_as_data->kctx = NULL;
|
||||
|
||||
kbasep_js_clear_submit_allowed(&kbdev->js_data, kctx);
|
||||
/* If the GPU is currently powered, de-activate this address space on
|
||||
* the MMU */
|
||||
if (kbdev->pm.backend.gpu_powered)
|
||||
kbase_mmu_disable(kctx);
|
||||
/* If the GPU was not powered then the MMU will be reprogrammed on the
|
||||
* next pm_context_active() */
|
||||
|
||||
release_addr_space(kbdev, as_nr, kctx);
|
||||
kctx->as_nr = KBASEP_AS_NR_INVALID;
|
||||
}
|
||||
|
||||
void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
}
|
||||
|
||||
void kbase_backend_release_free_address_space(struct kbase_device *kbdev,
|
||||
int as_nr)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
|
||||
js_devdata->as_free |= (1 << as_nr);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_is_runpool_full - check whether the runpool is full for a specified
|
||||
* context
|
||||
* @kbdev: Kbase device
|
||||
* @kctx: Kbase context
|
||||
*
|
||||
* If kctx == NULL, then this makes the least restrictive check on the
|
||||
* runpool. A specific context that is supplied immediately after could fail
|
||||
* the check, even under the same conditions.
|
||||
*
|
||||
* Therefore, once a context is obtained you \b must re-check it with this
|
||||
* function, since the return value could change to false.
|
||||
*
|
||||
* Context:
|
||||
* In all cases, the caller must hold kbasep_js_device_data.runpool_mutex.
|
||||
* When kctx != NULL the caller must hold the
|
||||
* kbasep_js_kctx_info.ctx.jsctx_mutex.
|
||||
* When kctx == NULL, then the caller need not hold any jsctx_mutex locks (but
|
||||
* it doesn't do any harm to do so).
|
||||
*
|
||||
* Return: true if the runpool is full
|
||||
*/
|
||||
static bool check_is_runpool_full(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
bool is_runpool_full;
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
|
||||
/* Regardless of whether a context is submitting or not, can't have more
|
||||
* than there are HW address spaces */
|
||||
is_runpool_full = (bool) (js_devdata->nr_all_contexts_running >=
|
||||
kbdev->nr_hw_address_spaces);
|
||||
|
||||
if (kctx != NULL && (kctx->jctx.sched_info.ctx.flags &
|
||||
KBASE_CTX_FLAG_SUBMIT_DISABLED) == 0) {
|
||||
lockdep_assert_held(&kctx->jctx.sched_info.ctx.jsctx_mutex);
|
||||
/* Contexts that submit might use less of the address spaces
|
||||
* available, due to HW workarounds. In which case, the runpool
|
||||
* is also full when the number of submitting contexts exceeds
|
||||
* the number of submittable address spaces.
|
||||
*
|
||||
* Both checks must be made: can have nr_user_address_spaces ==
|
||||
* nr_hw_address spaces, and at the same time can have
|
||||
* nr_user_contexts_running < nr_all_contexts_running. */
|
||||
is_runpool_full |= (bool)
|
||||
(js_devdata->nr_user_contexts_running >=
|
||||
kbdev->nr_user_address_spaces);
|
||||
}
|
||||
|
||||
return is_runpool_full;
|
||||
}
|
||||
|
||||
int kbase_backend_find_free_address_space(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
struct kbasep_js_kctx_info *js_kctx_info;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
js_kctx_info = &kctx->jctx.sched_info;
|
||||
|
||||
mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
|
||||
/* First try to find a free address space */
|
||||
if (check_is_runpool_full(kbdev, kctx))
|
||||
i = -1;
|
||||
else
|
||||
i = ffs(js_devdata->as_free) - 1;
|
||||
|
||||
if (i >= 0 && i < kbdev->nr_hw_address_spaces) {
|
||||
js_devdata->as_free &= ~(1 << i);
|
||||
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
|
||||
|
||||
/* No address space currently free, see if we can release one */
|
||||
for (i = 0; i < kbdev->nr_hw_address_spaces; i++) {
|
||||
struct kbasep_js_per_as_data *js_per_as_data;
|
||||
struct kbasep_js_kctx_info *as_js_kctx_info;
|
||||
struct kbase_context *as_kctx;
|
||||
|
||||
js_per_as_data = &kbdev->js_data.runpool_irq.per_as_data[i];
|
||||
as_kctx = js_per_as_data->kctx;
|
||||
as_js_kctx_info = &as_kctx->jctx.sched_info;
|
||||
|
||||
/* Don't release privileged or active contexts, or contexts with
|
||||
* jobs running */
|
||||
if (as_kctx && !(as_kctx->jctx.sched_info.ctx.flags &
|
||||
KBASE_CTX_FLAG_PRIVILEGED) &&
|
||||
js_per_as_data->as_busy_refcount == 0) {
|
||||
if (!kbasep_js_runpool_retain_ctx_nolock(kbdev,
|
||||
as_kctx)) {
|
||||
WARN(1, "Failed to retain active context\n");
|
||||
|
||||
spin_unlock_irqrestore(
|
||||
&js_devdata->runpool_irq.lock,
|
||||
flags);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
return KBASEP_AS_NR_INVALID;
|
||||
}
|
||||
|
||||
kbasep_js_clear_submit_allowed(js_devdata, as_kctx);
|
||||
|
||||
/* Drop and retake locks to take the jsctx_mutex on the
|
||||
* context we're about to release without violating lock
|
||||
* ordering
|
||||
*/
|
||||
spin_unlock_irqrestore(&js_devdata->runpool_irq.lock,
|
||||
flags);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
|
||||
/* Release context from address space */
|
||||
mutex_lock(&as_js_kctx_info->ctx.jsctx_mutex);
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
|
||||
kbasep_js_runpool_release_ctx_nolock(kbdev, as_kctx);
|
||||
|
||||
if (!as_js_kctx_info->ctx.is_scheduled) {
|
||||
kbasep_js_runpool_requeue_or_kill_ctx(kbdev,
|
||||
as_kctx,
|
||||
true);
|
||||
|
||||
js_devdata->as_free &= ~(1 << i);
|
||||
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Context was retained while locks were dropped,
|
||||
* continue looking for free AS */
|
||||
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&as_js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
|
||||
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
|
||||
return KBASEP_AS_NR_INVALID;
|
||||
}
|
||||
|
||||
bool kbase_backend_use_ctx(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
int as_nr)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
struct kbasep_js_kctx_info *js_kctx_info;
|
||||
struct kbase_as *new_address_space = NULL;
|
||||
|
||||
js_devdata = &kbdev->js_data;
|
||||
js_kctx_info = &kctx->jctx.sched_info;
|
||||
|
||||
if (kbdev->hwaccess.active_kctx == kctx ||
|
||||
kctx->as_nr != KBASEP_AS_NR_INVALID ||
|
||||
as_nr == KBASEP_AS_NR_INVALID) {
|
||||
WARN(1, "Invalid parameters to use_ctx()\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
new_address_space = &kbdev->as[as_nr];
|
||||
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
lockdep_assert_held(&new_address_space->transaction_mutex);
|
||||
lockdep_assert_held(&js_devdata->runpool_irq.lock);
|
||||
|
||||
assign_and_activate_kctx_addr_space(kbdev, kctx, new_address_space);
|
||||
|
||||
if ((js_kctx_info->ctx.flags & KBASE_CTX_FLAG_PRIVILEGED) != 0) {
|
||||
/* We need to retain it to keep the corresponding address space
|
||||
*/
|
||||
kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
115
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_defs.h
Normal file
115
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_defs.h
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register-based HW access backend specific definitions
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_GPU_DEFS_H_
|
||||
#define _KBASE_HWACCESS_GPU_DEFS_H_
|
||||
|
||||
/* SLOT_RB_SIZE must be < 256 */
|
||||
#define SLOT_RB_SIZE 2
|
||||
#define SLOT_RB_MASK (SLOT_RB_SIZE - 1)
|
||||
|
||||
/**
|
||||
* struct rb_entry - Ringbuffer entry
|
||||
* @katom: Atom associated with this entry
|
||||
*/
|
||||
struct rb_entry {
|
||||
struct kbase_jd_atom *katom;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct slot_rb - Slot ringbuffer
|
||||
* @entries: Ringbuffer entries
|
||||
* @last_context: The last context to submit a job on this slot
|
||||
* @read_idx: Current read index of buffer
|
||||
* @write_idx: Current write index of buffer
|
||||
* @job_chain_flag: Flag used to implement jobchain disambiguation
|
||||
*/
|
||||
struct slot_rb {
|
||||
struct rb_entry entries[SLOT_RB_SIZE];
|
||||
|
||||
struct kbase_context *last_context;
|
||||
|
||||
u8 read_idx;
|
||||
u8 write_idx;
|
||||
|
||||
u8 job_chain_flag;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kbase_backend_data - GPU backend specific data for HW access layer
|
||||
* @slot_rb: Slot ringbuffers
|
||||
* @rmu_workaround_flag: When PRLAM-8987 is present, this flag determines
|
||||
* whether slots 0/1 or slot 2 are currently being
|
||||
* pulled from
|
||||
* @scheduling_timer: The timer tick used for rescheduling jobs
|
||||
* @timer_running: Is the timer running? The runpool_mutex must be
|
||||
* held whilst modifying this.
|
||||
* @reset_gpu: Set to a KBASE_RESET_xxx value (see comments)
|
||||
* @reset_workq: Work queue for performing the reset
|
||||
* @reset_work: Work item for performing the reset
|
||||
* @reset_wait: Wait event signalled when the reset is complete
|
||||
* @reset_timer: Timeout for soft-stops before the reset
|
||||
*
|
||||
* The kbasep_js_device_data::runpool_irq::lock (a spinlock) must be held when
|
||||
* accessing this structure
|
||||
*/
|
||||
struct kbase_backend_data {
|
||||
struct slot_rb slot_rb[BASE_JM_MAX_NR_SLOTS];
|
||||
|
||||
bool rmu_workaround_flag;
|
||||
|
||||
struct hrtimer scheduling_timer;
|
||||
|
||||
bool timer_running;
|
||||
|
||||
atomic_t reset_gpu;
|
||||
|
||||
/* The GPU reset isn't pending */
|
||||
#define KBASE_RESET_GPU_NOT_PENDING 0
|
||||
/* kbase_prepare_to_reset_gpu has been called */
|
||||
#define KBASE_RESET_GPU_PREPARED 1
|
||||
/* kbase_reset_gpu has been called - the reset will now definitely happen
|
||||
* within the timeout period */
|
||||
#define KBASE_RESET_GPU_COMMITTED 2
|
||||
/* The GPU reset process is currently occuring (timeout has expired or
|
||||
* kbasep_try_reset_gpu_early was called) */
|
||||
#define KBASE_RESET_GPU_HAPPENING 3
|
||||
|
||||
struct workqueue_struct *reset_workq;
|
||||
struct work_struct reset_work;
|
||||
wait_queue_head_t reset_wait;
|
||||
struct hrtimer reset_timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kbase_jd_atom_backend - GPU backend specific katom data
|
||||
*/
|
||||
struct kbase_jd_atom_backend {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kbase_context_backend - GPU backend specific context data
|
||||
*/
|
||||
struct kbase_context_backend {
|
||||
};
|
||||
|
||||
#endif /* _KBASE_HWACCESS_GPU_DEFS_H_ */
|
||||
1629
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_hw.c
Normal file
1629
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_hw.c
Normal file
File diff suppressed because it is too large
Load diff
155
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_internal.h
Normal file
155
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_internal.h
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Job Manager backend-specific low-level APIs.
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_JM_HWACCESS_H_
|
||||
#define _KBASE_JM_HWACCESS_H_
|
||||
|
||||
#include <mali_kbase_hw.h>
|
||||
#include <mali_kbase_debug.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include <backend/gpu/mali_kbase_jm_rb.h>
|
||||
|
||||
/**
|
||||
* kbase_job_submit_nolock() - Submit a job to a certain job-slot
|
||||
* @kbdev: Device pointer
|
||||
* @katom: Atom to submit
|
||||
* @js: Job slot to submit on
|
||||
*
|
||||
* The caller must check kbasep_jm_is_submit_slots_free() != false before
|
||||
* calling this.
|
||||
*
|
||||
* The following locking conditions are made on the caller:
|
||||
* - it must hold the kbasep_js_device_data::runpoool_irq::lock
|
||||
*/
|
||||
void kbase_job_submit_nolock(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom, int js);
|
||||
|
||||
/**
|
||||
* kbase_job_done_slot() - Complete the head job on a particular job-slot
|
||||
* @kbdev: Device pointer
|
||||
* @s: Job slot
|
||||
* @completion_code: Completion code of job reported by GPU
|
||||
* @job_tail: Job tail address reported by GPU
|
||||
* @end_timestamp: Timestamp of job completion
|
||||
*/
|
||||
void kbase_job_done_slot(struct kbase_device *kbdev, int s, u32 completion_code,
|
||||
u64 job_tail, ktime_t *end_timestamp);
|
||||
|
||||
#ifdef CONFIG_GPU_TRACEPOINTS
|
||||
static inline char *kbasep_make_job_slot_string(int js, char *js_string)
|
||||
{
|
||||
sprintf(js_string, "job_slot_%i", js);
|
||||
return js_string;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kbase_job_hw_submit() - Submit a job to the GPU
|
||||
* @kbdev: Device pointer
|
||||
* @katom: Atom to submit
|
||||
* @js: Job slot to submit on
|
||||
*
|
||||
* The caller must check kbasep_jm_is_submit_slots_free() != false before
|
||||
* calling this.
|
||||
*
|
||||
* The following locking conditions are made on the caller:
|
||||
* - it must hold the kbasep_js_device_data::runpoool_irq::lock
|
||||
*/
|
||||
void kbase_job_hw_submit(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom,
|
||||
int js);
|
||||
|
||||
/**
|
||||
* kbasep_job_slot_soft_or_hard_stop_do_action() - Perform a soft or hard stop
|
||||
* on the specified atom
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to stop on
|
||||
* @action: The action to perform, either JSn_COMMAND_HARD_STOP or
|
||||
* JSn_COMMAND_SOFT_STOP
|
||||
* @core_reqs: Core requirements of atom to stop
|
||||
* @target_katom: Atom to stop
|
||||
*
|
||||
* The following locking conditions are made on the caller:
|
||||
* - it must hold the kbasep_js_device_data::runpool_irq::lock
|
||||
*/
|
||||
void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
|
||||
int js,
|
||||
u32 action,
|
||||
u16 core_reqs,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
|
||||
/**
|
||||
* kbase_backend_soft_hard_stop_slot() - Soft or hard stop jobs on a given job
|
||||
* slot belonging to a given context.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer. May be NULL
|
||||
* @katom: Specific atom to stop. May be NULL
|
||||
* @js: Job slot to hard stop
|
||||
* @action: The action to perform, either JSn_COMMAND_HARD_STOP or
|
||||
* JSn_COMMAND_SOFT_STOP
|
||||
*
|
||||
* If no context is provided then all jobs on the slot will be soft or hard
|
||||
* stopped.
|
||||
*
|
||||
* If a katom is provided then only that specific atom will be stopped. In this
|
||||
* case the kctx parameter is ignored.
|
||||
*
|
||||
* Jobs that are on the slot but are not yet on the GPU will be unpulled and
|
||||
* returned to the job scheduler.
|
||||
*
|
||||
* Return: true if an atom was stopped, false otherwise
|
||||
*/
|
||||
bool kbase_backend_soft_hard_stop_slot(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
int js,
|
||||
struct kbase_jd_atom *katom,
|
||||
u32 action);
|
||||
|
||||
/**
|
||||
* kbase_job_slot_init - Initialise job slot framework
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Called on driver initialisation
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_job_slot_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_job_slot_halt - Halt the job slot framework
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Should prevent any further job slot processing
|
||||
*/
|
||||
void kbase_job_slot_halt(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_job_slot_term - Terminate job slot framework
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Called on driver termination
|
||||
*/
|
||||
void kbase_job_slot_term(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_JM_HWACCESS_H_ */
|
||||
1497
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_rb.c
Normal file
1497
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_rb.c
Normal file
File diff suppressed because it is too large
Load diff
87
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_rb.h
Normal file
87
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_jm_rb.h
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register-based HW access backend specific APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_GPU_H_
|
||||
#define _KBASE_HWACCESS_GPU_H_
|
||||
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
/**
|
||||
* kbase_gpu_irq_evict - Evict an atom from a NEXT slot
|
||||
*
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to evict from
|
||||
*
|
||||
* Evict the atom in the NEXT slot for the specified job slot. This function is
|
||||
* called from the job complete IRQ handler when the previous job has failed.
|
||||
*
|
||||
* Return: true if job evicted from NEXT registers, false otherwise
|
||||
*/
|
||||
bool kbase_gpu_irq_evict(struct kbase_device *kbdev, int js);
|
||||
|
||||
/**
|
||||
* kbase_gpu_complete_hw - Complete an atom on job slot js
|
||||
*
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot that has completed
|
||||
* @completion_code: Event code from job that has completed
|
||||
* @job_tail: The tail address from the hardware if the job has partially
|
||||
* completed
|
||||
* @end_timestamp: Time of completion
|
||||
*/
|
||||
void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js,
|
||||
u32 completion_code,
|
||||
u64 job_tail,
|
||||
ktime_t *end_timestamp);
|
||||
|
||||
/**
|
||||
* kbase_gpu_inspect - Inspect the contents of the HW access ringbuffer
|
||||
*
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
* @idx: Index into ringbuffer. 0 is the job currently running on
|
||||
* the slot, 1 is the job waiting, all other values are invalid.
|
||||
* Return: The atom at that position in the ringbuffer
|
||||
* or NULL if no atom present
|
||||
*/
|
||||
struct kbase_jd_atom *kbase_gpu_inspect(struct kbase_device *kbdev, int js,
|
||||
int idx);
|
||||
|
||||
/**
|
||||
* kbase_gpu_slot_update - Update state based on slot ringbuffers
|
||||
*
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Inspect the jobs in the slot ringbuffers and update state.
|
||||
*
|
||||
* This will cause jobs to be submitted to hardware if they are unblocked
|
||||
*/
|
||||
void kbase_gpu_slot_update(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_gpu_dump_slots - Print the contents of the slot ringbuffers
|
||||
*
|
||||
* @kbdev: Device pointer
|
||||
*/
|
||||
void kbase_gpu_dump_slots(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_GPU_H_ */
|
||||
295
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_affinity.c
Normal file
295
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_affinity.c
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel affinity manager APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include "mali_kbase_js_affinity.h"
|
||||
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
|
||||
bool kbase_js_can_run_job_on_slot_no_lock(struct kbase_device *kbdev,
|
||||
int js)
|
||||
{
|
||||
/*
|
||||
* Here are the reasons for using job slot 2:
|
||||
* - BASE_HW_ISSUE_8987 (which is entirely used for that purpose)
|
||||
* - In absence of the above, then:
|
||||
* - Atoms with BASE_JD_REQ_COHERENT_GROUP
|
||||
* - But, only when there aren't contexts with
|
||||
* KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES, because the atoms that run on
|
||||
* all cores on slot 1 could be blocked by those using a coherent group
|
||||
* on slot 2
|
||||
* - And, only when you actually have 2 or more coregroups - if you
|
||||
* only have 1 coregroup, then having jobs for slot 2 implies they'd
|
||||
* also be for slot 1, meaning you'll get interference from them. Jobs
|
||||
* able to run on slot 2 could also block jobs that can only run on
|
||||
* slot 1 (tiler jobs)
|
||||
*/
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8987))
|
||||
return true;
|
||||
|
||||
if (js != 2)
|
||||
return true;
|
||||
|
||||
/* Only deal with js==2 now: */
|
||||
if (kbdev->gpu_props.num_core_groups > 1) {
|
||||
/* Only use slot 2 in the 2+ coregroup case */
|
||||
if (kbasep_js_ctx_attr_is_attr_on_runpool(kbdev,
|
||||
KBASEP_JS_CTX_ATTR_COMPUTE_ALL_CORES) ==
|
||||
false) {
|
||||
/* ...But only when we *don't* have atoms that run on
|
||||
* all cores */
|
||||
|
||||
/* No specific check for BASE_JD_REQ_COHERENT_GROUP
|
||||
* atoms - the policy will sort that out */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Above checks failed mean we shouldn't use slot 2 */
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* As long as it has been decided to have a deeper modification of
|
||||
* what job scheduler, power manager and affinity manager will
|
||||
* implement, this function is just an intermediate step that
|
||||
* assumes:
|
||||
* - all working cores will be powered on when this is called.
|
||||
* - largest current configuration is 2 core groups.
|
||||
* - It has been decided not to have hardcoded values so the low
|
||||
* and high cores in a core split will be evently distributed.
|
||||
* - Odd combinations of core requirements have been filtered out
|
||||
* and do not get to this function (e.g. CS+T+NSS is not
|
||||
* supported here).
|
||||
* - This function is frequently called and can be optimized,
|
||||
* (see notes in loops), but as the functionallity will likely
|
||||
* be modified, optimization has not been addressed.
|
||||
*/
|
||||
bool kbase_js_choose_affinity(u64 * const affinity,
|
||||
struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom, int js)
|
||||
{
|
||||
base_jd_core_req core_req = katom->core_req;
|
||||
unsigned int num_core_groups = kbdev->gpu_props.num_core_groups;
|
||||
u64 core_availability_mask;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
core_availability_mask = kbase_pm_ca_get_core_mask(kbdev);
|
||||
|
||||
/*
|
||||
* If no cores are currently available (core availability policy is
|
||||
* transitioning) then fail.
|
||||
*/
|
||||
if (0 == core_availability_mask) {
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
*affinity = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
KBASE_DEBUG_ASSERT(js >= 0);
|
||||
|
||||
if ((core_req & (BASE_JD_REQ_FS | BASE_JD_REQ_CS | BASE_JD_REQ_T)) ==
|
||||
BASE_JD_REQ_T) {
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
/* Tiler only job, bit 0 needed to enable tiler but no shader
|
||||
* cores required */
|
||||
*affinity = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (1 == kbdev->gpu_props.num_cores) {
|
||||
/* trivial case only one core, nothing to do */
|
||||
*affinity = core_availability_mask;
|
||||
} else {
|
||||
if ((core_req & (BASE_JD_REQ_COHERENT_GROUP |
|
||||
BASE_JD_REQ_SPECIFIC_COHERENT_GROUP))) {
|
||||
if (js == 0 || num_core_groups == 1) {
|
||||
/* js[0] and single-core-group systems just get
|
||||
* the first core group */
|
||||
*affinity =
|
||||
kbdev->gpu_props.props.coherency_info.group[0].core_mask
|
||||
& core_availability_mask;
|
||||
} else {
|
||||
/* js[1], js[2] use core groups 0, 1 for
|
||||
* dual-core-group systems */
|
||||
u32 core_group_idx = ((u32) js) - 1;
|
||||
|
||||
KBASE_DEBUG_ASSERT(core_group_idx <
|
||||
num_core_groups);
|
||||
*affinity =
|
||||
kbdev->gpu_props.props.coherency_info.group[core_group_idx].core_mask
|
||||
& core_availability_mask;
|
||||
|
||||
/* If the job is specifically targeting core
|
||||
* group 1 and the core availability policy is
|
||||
* keeping that core group off, then fail */
|
||||
if (*affinity == 0 && core_group_idx == 1 &&
|
||||
kbdev->pm.backend.cg1_disabled
|
||||
== true)
|
||||
katom->event_code =
|
||||
BASE_JD_EVENT_PM_EVENT;
|
||||
}
|
||||
} else {
|
||||
/* All cores are available when no core split is
|
||||
* required */
|
||||
*affinity = core_availability_mask;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
/*
|
||||
* If no cores are currently available in the desired core group(s)
|
||||
* (core availability policy is transitioning) then fail.
|
||||
*/
|
||||
if (*affinity == 0)
|
||||
return false;
|
||||
|
||||
/* Enable core 0 if tiler required */
|
||||
if (core_req & BASE_JD_REQ_T)
|
||||
*affinity = *affinity | 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool kbase_js_affinity_is_violating(
|
||||
struct kbase_device *kbdev,
|
||||
u64 *affinities)
|
||||
{
|
||||
/* This implementation checks whether the two slots involved in Generic
|
||||
* thread creation have intersecting affinity. This is due to micro-
|
||||
* architectural issues where a job in slot A targetting cores used by
|
||||
* slot B could prevent the job in slot B from making progress until the
|
||||
* job in slot A has completed.
|
||||
*/
|
||||
u64 affinity_set_left;
|
||||
u64 affinity_set_right;
|
||||
u64 intersection;
|
||||
|
||||
KBASE_DEBUG_ASSERT(affinities != NULL);
|
||||
|
||||
affinity_set_left = affinities[1];
|
||||
|
||||
affinity_set_right = affinities[2];
|
||||
|
||||
/* A violation occurs when any bit in the left_set is also in the
|
||||
* right_set */
|
||||
intersection = affinity_set_left & affinity_set_right;
|
||||
|
||||
return (bool) (intersection != (u64) 0u);
|
||||
}
|
||||
|
||||
bool kbase_js_affinity_would_violate(struct kbase_device *kbdev, int js,
|
||||
u64 affinity)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
u64 new_affinities[BASE_JM_MAX_NR_SLOTS];
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS);
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
memcpy(new_affinities, js_devdata->runpool_irq.slot_affinities,
|
||||
sizeof(js_devdata->runpool_irq.slot_affinities));
|
||||
|
||||
new_affinities[js] |= affinity;
|
||||
|
||||
return kbase_js_affinity_is_violating(kbdev, new_affinities);
|
||||
}
|
||||
|
||||
void kbase_js_affinity_retain_slot_cores(struct kbase_device *kbdev, int js,
|
||||
u64 affinity)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
u64 cores;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS);
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbase_js_affinity_would_violate(kbdev, js, affinity)
|
||||
== false);
|
||||
|
||||
cores = affinity;
|
||||
while (cores) {
|
||||
int bitnum = fls64(cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
s8 cnt;
|
||||
|
||||
cnt =
|
||||
++(js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum]);
|
||||
|
||||
if (cnt == 1)
|
||||
js_devdata->runpool_irq.slot_affinities[js] |= bit;
|
||||
|
||||
cores &= ~bit;
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_js_affinity_release_slot_cores(struct kbase_device *kbdev, int js,
|
||||
u64 affinity)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
u64 cores;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(js < BASE_JM_MAX_NR_SLOTS);
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
cores = affinity;
|
||||
while (cores) {
|
||||
int bitnum = fls64(cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
s8 cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(
|
||||
js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum] > 0);
|
||||
|
||||
cnt =
|
||||
--(js_devdata->runpool_irq.slot_affinity_refcount[js][bitnum]);
|
||||
|
||||
if (0 == cnt)
|
||||
js_devdata->runpool_irq.slot_affinities[js] &= ~bit;
|
||||
|
||||
cores &= ~bit;
|
||||
}
|
||||
}
|
||||
|
||||
#if KBASE_TRACE_ENABLE
|
||||
void kbase_js_debug_log_current_affinities(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
int slot_nr;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
for (slot_nr = 0; slot_nr < 3; ++slot_nr)
|
||||
KBASE_TRACE_ADD_SLOT_INFO(kbdev, JS_AFFINITY_CURRENT, NULL,
|
||||
NULL, 0u, slot_nr,
|
||||
(u32) js_devdata->runpool_irq.slot_affinities[slot_nr]);
|
||||
}
|
||||
#endif /* KBASE_TRACE_ENABLE */
|
||||
138
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_affinity.h
Normal file
138
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_affinity.h
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Affinity Manager internal APIs.
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_JS_AFFINITY_H_
|
||||
#define _KBASE_JS_AFFINITY_H_
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG_SHADER_SPLIT_FS
|
||||
/* Import the external affinity mask variables */
|
||||
extern u64 mali_js0_affinity_mask;
|
||||
extern u64 mali_js1_affinity_mask;
|
||||
extern u64 mali_js2_affinity_mask;
|
||||
#endif /* CONFIG_MALI_DEBUG_SHADER_SPLIT_FS */
|
||||
|
||||
|
||||
/**
|
||||
* kbase_js_can_run_job_on_slot_no_lock - Decide whether it is possible to
|
||||
* submit a job to a particular job slot in the current status
|
||||
*
|
||||
* @kbdev: The kbase device structure of the device
|
||||
* @js: Job slot number to check for allowance
|
||||
*
|
||||
* Will check if submitting to the given job slot is allowed in the current
|
||||
* status. For example using job slot 2 while in soft-stoppable state and only
|
||||
* having 1 coregroup is not allowed by the policy. This function should be
|
||||
* called prior to submitting a job to a slot to make sure policy rules are not
|
||||
* violated.
|
||||
*
|
||||
* The following locking conditions are made on the caller
|
||||
* - it must hold kbasep_js_device_data.runpool_irq.lock
|
||||
*/
|
||||
bool kbase_js_can_run_job_on_slot_no_lock(struct kbase_device *kbdev,
|
||||
int js);
|
||||
|
||||
/**
|
||||
* kbase_js_choose_affinity - Compute affinity for a given job.
|
||||
*
|
||||
* @affinity: Affinity bitmap computed
|
||||
* @kbdev: The kbase device structure of the device
|
||||
* @katom: Job chain of which affinity is going to be found
|
||||
* @js: Slot the job chain is being submitted
|
||||
*
|
||||
* Currently assumes an all-on/all-off power management policy.
|
||||
* Also assumes there is at least one core with tiler available.
|
||||
*
|
||||
* Returns true if a valid affinity was chosen, false if
|
||||
* no cores were available.
|
||||
*/
|
||||
bool kbase_js_choose_affinity(u64 * const affinity,
|
||||
struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom,
|
||||
int js);
|
||||
|
||||
/**
|
||||
* kbase_js_affinity_would_violate - Determine whether a proposed affinity on
|
||||
* job slot @js would cause a violation of affinity restrictions.
|
||||
*
|
||||
* @kbdev: Kbase device structure
|
||||
* @js: The job slot to test
|
||||
* @affinity: The affinity mask to test
|
||||
*
|
||||
* The following locks must be held by the caller
|
||||
* - kbasep_js_device_data.runpool_irq.lock
|
||||
*
|
||||
* Return: true if the affinity would violate the restrictions
|
||||
*/
|
||||
bool kbase_js_affinity_would_violate(struct kbase_device *kbdev, int js,
|
||||
u64 affinity);
|
||||
|
||||
/**
|
||||
* kbase_js_affinity_retain_slot_cores - Affinity tracking: retain cores used by
|
||||
* a slot
|
||||
*
|
||||
* @kbdev: Kbase device structure
|
||||
* @js: The job slot retaining the cores
|
||||
* @affinity: The cores to retain
|
||||
*
|
||||
* The following locks must be held by the caller
|
||||
* - kbasep_js_device_data.runpool_irq.lock
|
||||
*/
|
||||
void kbase_js_affinity_retain_slot_cores(struct kbase_device *kbdev, int js,
|
||||
u64 affinity);
|
||||
|
||||
/**
|
||||
* kbase_js_affinity_release_slot_cores - Affinity tracking: release cores used
|
||||
* by a slot
|
||||
*
|
||||
* @kbdev: Kbase device structure
|
||||
* @js: Job slot
|
||||
* @affinity: Bit mask of core to be released
|
||||
*
|
||||
* Cores must be released as soon as a job is dequeued from a slot's 'submit
|
||||
* slots', and before another job is submitted to those slots. Otherwise, the
|
||||
* refcount could exceed the maximum number submittable to a slot,
|
||||
* %BASE_JM_SUBMIT_SLOTS.
|
||||
*
|
||||
* The following locks must be held by the caller
|
||||
* - kbasep_js_device_data.runpool_irq.lock
|
||||
*/
|
||||
void kbase_js_affinity_release_slot_cores(struct kbase_device *kbdev, int js,
|
||||
u64 affinity);
|
||||
|
||||
/**
|
||||
* kbase_js_debug_log_current_affinities - log the current affinities
|
||||
*
|
||||
* @kbdev: Kbase device structure
|
||||
*
|
||||
* Output to the Trace log the current tracked affinities on all slots
|
||||
*/
|
||||
#if KBASE_TRACE_ENABLE
|
||||
void kbase_js_debug_log_current_affinities(struct kbase_device *kbdev);
|
||||
#else /* KBASE_TRACE_ENABLE */
|
||||
static inline void
|
||||
kbase_js_debug_log_current_affinities(struct kbase_device *kbdev)
|
||||
{
|
||||
}
|
||||
#endif /* KBASE_TRACE_ENABLE */
|
||||
|
||||
#endif /* _KBASE_JS_AFFINITY_H_ */
|
||||
319
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_backend.c
Normal file
319
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_js_backend.c
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register-based HW access backend specific job scheduler APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_hwaccess_jm.h>
|
||||
#include <backend/gpu/mali_kbase_jm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_js_internal.h>
|
||||
|
||||
/*
|
||||
* Define for when dumping is enabled.
|
||||
* This should not be based on the instrumentation level as whether dumping is
|
||||
* enabled for a particular level is down to the integrator. However this is
|
||||
* being used for now as otherwise the cinstr headers would be needed.
|
||||
*/
|
||||
#define CINSTR_DUMPING_ENABLED (2 == MALI_INSTRUMENTATION_LEVEL)
|
||||
|
||||
/*
|
||||
* Hold the runpool_mutex for this
|
||||
*/
|
||||
static inline bool timer_callback_should_run(struct kbase_device *kbdev)
|
||||
{
|
||||
s8 nr_running_ctxs;
|
||||
|
||||
lockdep_assert_held(&kbdev->js_data.runpool_mutex);
|
||||
|
||||
/* nr_contexts_pullable is updated with the runpool_mutex. However, the
|
||||
* locking in the caller gives us a barrier that ensures
|
||||
* nr_contexts_pullable is up-to-date for reading */
|
||||
nr_running_ctxs = atomic_read(&kbdev->js_data.nr_contexts_runnable);
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
if (kbdev->js_data.softstop_always) {
|
||||
/* Debug support for allowing soft-stop on a single context */
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9435)) {
|
||||
/* Timeouts would have to be 4x longer (due to micro-
|
||||
* architectural design) to support OpenCL conformance tests, so
|
||||
* only run the timer when there's:
|
||||
* - 2 or more CL contexts
|
||||
* - 1 or more GLES contexts
|
||||
*
|
||||
* NOTE: We will treat a context that has both Compute and Non-
|
||||
* Compute jobs will be treated as an OpenCL context (hence, we
|
||||
* don't check KBASEP_JS_CTX_ATTR_NON_COMPUTE).
|
||||
*/
|
||||
{
|
||||
s8 nr_compute_ctxs =
|
||||
kbasep_js_ctx_attr_count_on_runpool(kbdev,
|
||||
KBASEP_JS_CTX_ATTR_COMPUTE);
|
||||
s8 nr_noncompute_ctxs = nr_running_ctxs -
|
||||
nr_compute_ctxs;
|
||||
|
||||
return (bool) (nr_compute_ctxs >= 2 ||
|
||||
nr_noncompute_ctxs > 0);
|
||||
}
|
||||
} else {
|
||||
/* Run the timer callback whenever you have at least 1 context
|
||||
*/
|
||||
return (bool) (nr_running_ctxs > 0);
|
||||
}
|
||||
}
|
||||
|
||||
static enum hrtimer_restart timer_callback(struct hrtimer *timer)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev;
|
||||
struct kbasep_js_device_data *js_devdata;
|
||||
struct kbase_backend_data *backend;
|
||||
int s;
|
||||
bool reset_needed = false;
|
||||
|
||||
KBASE_DEBUG_ASSERT(timer != NULL);
|
||||
|
||||
backend = container_of(timer, struct kbase_backend_data,
|
||||
scheduling_timer);
|
||||
kbdev = container_of(backend, struct kbase_device, hwaccess.backend);
|
||||
js_devdata = &kbdev->js_data;
|
||||
|
||||
/* Loop through the slots */
|
||||
spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
|
||||
for (s = 0; s < kbdev->gpu_props.num_job_slots; s++) {
|
||||
struct kbase_jd_atom *atom = NULL;
|
||||
|
||||
if (kbase_backend_nr_atoms_on_slot(kbdev, s) > 0) {
|
||||
atom = kbase_gpu_inspect(kbdev, s, 0);
|
||||
KBASE_DEBUG_ASSERT(atom != NULL);
|
||||
}
|
||||
|
||||
if (atom != NULL) {
|
||||
/* The current version of the model doesn't support
|
||||
* Soft-Stop */
|
||||
if (!kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_5736)) {
|
||||
u32 ticks = atom->sched_info.cfs.ticks++;
|
||||
|
||||
#if !CINSTR_DUMPING_ENABLED
|
||||
u32 soft_stop_ticks, hard_stop_ticks,
|
||||
gpu_reset_ticks;
|
||||
if (atom->core_req & BASE_JD_REQ_ONLY_COMPUTE) {
|
||||
soft_stop_ticks =
|
||||
js_devdata->soft_stop_ticks_cl;
|
||||
hard_stop_ticks =
|
||||
js_devdata->hard_stop_ticks_cl;
|
||||
gpu_reset_ticks =
|
||||
js_devdata->gpu_reset_ticks_cl;
|
||||
} else {
|
||||
soft_stop_ticks =
|
||||
js_devdata->soft_stop_ticks;
|
||||
hard_stop_ticks =
|
||||
js_devdata->hard_stop_ticks_ss;
|
||||
gpu_reset_ticks =
|
||||
js_devdata->gpu_reset_ticks_ss;
|
||||
}
|
||||
|
||||
/* Job is Soft-Stoppable */
|
||||
if (ticks == soft_stop_ticks) {
|
||||
int disjoint_threshold =
|
||||
KBASE_DISJOINT_STATE_INTERLEAVED_CONTEXT_COUNT_THRESHOLD;
|
||||
u32 softstop_flags = 0u;
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->soft_stop_ticks ticks.
|
||||
* Soft stop the slot so we can run
|
||||
* other jobs.
|
||||
*/
|
||||
dev_dbg(kbdev->dev, "Soft-stop");
|
||||
#if !KBASE_DISABLE_SCHEDULING_SOFT_STOPS
|
||||
/* nr_user_contexts_running is updated
|
||||
* with the runpool_mutex, but we can't
|
||||
* take that here.
|
||||
*
|
||||
* However, if it's about to be
|
||||
* increased then the new context can't
|
||||
* run any jobs until they take the
|
||||
* runpool_irq lock, so it's OK to
|
||||
* observe the older value.
|
||||
*
|
||||
* Similarly, if it's about to be
|
||||
* decreased, the last job from another
|
||||
* context has already finished, so it's
|
||||
* not too bad that we observe the older
|
||||
* value and register a disjoint event
|
||||
* when we try soft-stopping */
|
||||
if (js_devdata->nr_user_contexts_running
|
||||
>= disjoint_threshold)
|
||||
softstop_flags |=
|
||||
JS_COMMAND_SW_CAUSES_DISJOINT;
|
||||
|
||||
kbase_job_slot_softstop_swflags(kbdev,
|
||||
s, atom, softstop_flags);
|
||||
#endif
|
||||
} else if (ticks == hard_stop_ticks) {
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->hard_stop_ticks_ss ticks.
|
||||
* It should have been soft-stopped by
|
||||
* now. Hard stop the slot.
|
||||
*/
|
||||
#if !KBASE_DISABLE_SCHEDULING_HARD_STOPS
|
||||
int ms =
|
||||
js_devdata->scheduling_period_ns
|
||||
/ 1000000u;
|
||||
dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)",
|
||||
(unsigned long)ticks,
|
||||
(unsigned long)ms);
|
||||
kbase_job_slot_hardstop(atom->kctx, s,
|
||||
atom);
|
||||
#endif
|
||||
} else if (ticks == gpu_reset_ticks) {
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->gpu_reset_ticks_ss ticks.
|
||||
* It should have left the GPU by now.
|
||||
* Signal that the GPU needs to be
|
||||
* reset.
|
||||
*/
|
||||
reset_needed = true;
|
||||
}
|
||||
#else /* !CINSTR_DUMPING_ENABLED */
|
||||
/* NOTE: During CINSTR_DUMPING_ENABLED, we use
|
||||
* the alternate timeouts, which makes the hard-
|
||||
* stop and GPU reset timeout much longer. We
|
||||
* also ensure that we don't soft-stop at all.
|
||||
*/
|
||||
if (ticks == js_devdata->soft_stop_ticks) {
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->soft_stop_ticks. We do
|
||||
* not soft-stop during
|
||||
* CINSTR_DUMPING_ENABLED, however.
|
||||
*/
|
||||
dev_dbg(kbdev->dev, "Soft-stop");
|
||||
} else if (ticks ==
|
||||
js_devdata->hard_stop_ticks_dumping) {
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->hard_stop_ticks_dumping
|
||||
* ticks. Hard stop the slot.
|
||||
*/
|
||||
#if !KBASE_DISABLE_SCHEDULING_HARD_STOPS
|
||||
int ms =
|
||||
js_devdata->scheduling_period_ns
|
||||
/ 1000000u;
|
||||
dev_warn(kbdev->dev, "JS: Job Hard-Stopped (took more than %lu ticks at %lu ms/tick)",
|
||||
(unsigned long)ticks,
|
||||
(unsigned long)ms);
|
||||
kbase_job_slot_hardstop(atom->kctx, s,
|
||||
atom);
|
||||
#endif
|
||||
} else if (ticks ==
|
||||
js_devdata->gpu_reset_ticks_dumping) {
|
||||
/* Job has been scheduled for at least
|
||||
* js_devdata->gpu_reset_ticks_dumping
|
||||
* ticks. It should have left the GPU by
|
||||
* now. Signal that the GPU needs to be
|
||||
* reset.
|
||||
*/
|
||||
reset_needed = true;
|
||||
}
|
||||
#endif /* !CINSTR_DUMPING_ENABLED */
|
||||
}
|
||||
}
|
||||
}
|
||||
#if KBASE_GPU_RESET_EN
|
||||
if (reset_needed) {
|
||||
dev_err(kbdev->dev, "JS: Job has been on the GPU for too long (JS_RESET_TICKS_SS/DUMPING timeout hit). Issueing GPU soft-reset to resolve.");
|
||||
|
||||
if (kbase_prepare_to_reset_gpu_locked(kbdev))
|
||||
kbase_reset_gpu_locked(kbdev);
|
||||
}
|
||||
#endif /* KBASE_GPU_RESET_EN */
|
||||
/* the timer is re-issued if there is contexts in the run-pool */
|
||||
|
||||
if (backend->timer_running)
|
||||
hrtimer_start(&backend->scheduling_timer,
|
||||
HR_TIMER_DELAY_NSEC(js_devdata->scheduling_period_ns),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
void kbase_backend_ctx_count_changed(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
struct kbase_backend_data *backend = &kbdev->hwaccess.backend;
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&js_devdata->runpool_mutex);
|
||||
|
||||
if (!timer_callback_should_run(kbdev)) {
|
||||
/* Take spinlock to force synchronisation with timer */
|
||||
spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
|
||||
backend->timer_running = false;
|
||||
spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
|
||||
|
||||
/* From now on, return value of timer_callback_should_run() will
|
||||
* also cause the timer to not requeue itself. Its return value
|
||||
* cannot change, because it depends on variables updated with
|
||||
* the runpool_mutex held, which the caller of this must also
|
||||
* hold */
|
||||
hrtimer_cancel(&backend->scheduling_timer);
|
||||
}
|
||||
|
||||
if (timer_callback_should_run(kbdev) && !backend->timer_running) {
|
||||
/* Take spinlock to force synchronisation with timer */
|
||||
spin_lock_irqsave(&js_devdata->runpool_irq.lock, flags);
|
||||
backend->timer_running = true;
|
||||
spin_unlock_irqrestore(&js_devdata->runpool_irq.lock, flags);
|
||||
|
||||
hrtimer_start(&backend->scheduling_timer,
|
||||
HR_TIMER_DELAY_NSEC(js_devdata->scheduling_period_ns),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, JS_POLICY_TIMER_START, NULL, NULL, 0u,
|
||||
0u);
|
||||
}
|
||||
}
|
||||
|
||||
int kbase_backend_timer_init(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_backend_data *backend = &kbdev->hwaccess.backend;
|
||||
|
||||
hrtimer_init(&backend->scheduling_timer, CLOCK_MONOTONIC,
|
||||
HRTIMER_MODE_REL);
|
||||
backend->scheduling_timer.function = timer_callback;
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
backend->scheduling_timer.bounded_to_boot_cluster = true;
|
||||
#endif
|
||||
|
||||
backend->timer_running = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbase_backend_timer_term(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_backend_data *backend = &kbdev->hwaccess.backend;
|
||||
|
||||
hrtimer_cancel(&backend->scheduling_timer);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register-based HW access backend specific job scheduler APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_JS_BACKEND_H_
|
||||
#define _KBASE_JS_BACKEND_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_timer_init() - Initialise the JS scheduling timer
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function should be called at driver initialisation
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_backend_timer_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_backend_timer_term() - Terminate the JS scheduling timer
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function should be called at driver termination
|
||||
*/
|
||||
void kbase_backend_timer_term(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_JS_BACKEND_H_ */
|
||||
316
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_mmu_hw_direct.c
Normal file
316
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_mmu_hw_direct.c
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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/bitops.h>
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_mem.h>
|
||||
#include <mali_kbase_mmu_hw.h>
|
||||
#if defined(CONFIG_MALI_MIPE_ENABLED)
|
||||
#include <mali_kbase_tlstream.h>
|
||||
#endif
|
||||
#include <backend/gpu/mali_kbase_mmu_hw_direct.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
|
||||
static inline u64 lock_region(struct kbase_device *kbdev, u64 pfn,
|
||||
u32 num_pages)
|
||||
{
|
||||
u64 region;
|
||||
|
||||
/* can't lock a zero sized range */
|
||||
KBASE_DEBUG_ASSERT(num_pages);
|
||||
|
||||
region = pfn << PAGE_SHIFT;
|
||||
/*
|
||||
* fls returns (given the ASSERT above):
|
||||
* 1 .. 32
|
||||
*
|
||||
* 10 + fls(num_pages)
|
||||
* results in the range (11 .. 42)
|
||||
*/
|
||||
|
||||
/* gracefully handle num_pages being zero */
|
||||
if (0 == num_pages) {
|
||||
region |= 11;
|
||||
} else {
|
||||
u8 region_width;
|
||||
|
||||
region_width = 10 + fls(num_pages);
|
||||
if (num_pages != (1ul << (region_width - 11))) {
|
||||
/* not pow2, so must go up to the next pow2 */
|
||||
region_width += 1;
|
||||
}
|
||||
KBASE_DEBUG_ASSERT(region_width <= KBASE_LOCK_REGION_MAX_SIZE);
|
||||
KBASE_DEBUG_ASSERT(region_width >= KBASE_LOCK_REGION_MIN_SIZE);
|
||||
region |= region_width;
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
static int wait_ready(struct kbase_device *kbdev,
|
||||
unsigned int as_nr, struct kbase_context *kctx)
|
||||
{
|
||||
unsigned int max_loops = KBASE_AS_INACTIVE_MAX_LOOPS;
|
||||
u32 val = kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), kctx);
|
||||
|
||||
/* Wait for the MMU status to indicate there is no active command, in
|
||||
* case one is pending. Do not log remaining register accesses. */
|
||||
while (--max_loops && (val & AS_STATUS_AS_ACTIVE))
|
||||
val = kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), NULL);
|
||||
|
||||
if (max_loops == 0) {
|
||||
dev_err(kbdev->dev, "AS_ACTIVE bit stuck\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If waiting in loop was performed, log last read value. */
|
||||
if (KBASE_AS_INACTIVE_MAX_LOOPS - 1 > max_loops)
|
||||
kbase_reg_read(kbdev, MMU_AS_REG(as_nr, AS_STATUS), kctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_cmd(struct kbase_device *kbdev, int as_nr, u32 cmd,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* write AS_COMMAND when MMU is ready to accept another command */
|
||||
status = wait_ready(kbdev, as_nr, kctx);
|
||||
if (status == 0)
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as_nr, AS_COMMAND), cmd,
|
||||
kctx);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat)
|
||||
{
|
||||
const int num_as = 16;
|
||||
const int busfault_shift = MMU_PAGE_FAULT_FLAGS;
|
||||
const int pf_shift = 0;
|
||||
const unsigned long as_bit_mask = (1UL << num_as) - 1;
|
||||
unsigned long flags;
|
||||
u32 new_mask;
|
||||
u32 tmp;
|
||||
|
||||
/* bus faults */
|
||||
u32 bf_bits = (irq_stat >> busfault_shift) & as_bit_mask;
|
||||
/* page faults (note: Ignore ASes with both pf and bf) */
|
||||
u32 pf_bits = ((irq_stat >> pf_shift) & as_bit_mask) & ~bf_bits;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kbdev);
|
||||
|
||||
/* remember current mask */
|
||||
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
|
||||
new_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL);
|
||||
/* mask interrupts for now */
|
||||
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), 0, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
|
||||
|
||||
while (bf_bits | pf_bits) {
|
||||
struct kbase_as *as;
|
||||
int as_no;
|
||||
struct kbase_context *kctx;
|
||||
|
||||
/*
|
||||
* the while logic ensures we have a bit set, no need to check
|
||||
* for not-found here
|
||||
*/
|
||||
as_no = ffs(bf_bits | pf_bits) - 1;
|
||||
as = &kbdev->as[as_no];
|
||||
|
||||
/*
|
||||
* Refcount the kctx ASAP - it shouldn't disappear anyway, since
|
||||
* Bus/Page faults _should_ only occur whilst jobs are running,
|
||||
* and a job causing the Bus/Page fault shouldn't complete until
|
||||
* the MMU is updated
|
||||
*/
|
||||
kctx = kbasep_js_runpool_lookup_ctx(kbdev, as_no);
|
||||
|
||||
/* find faulting address */
|
||||
as->fault_addr = kbase_reg_read(kbdev,
|
||||
MMU_AS_REG(as_no,
|
||||
AS_FAULTADDRESS_HI),
|
||||
kctx);
|
||||
as->fault_addr <<= 32;
|
||||
as->fault_addr |= kbase_reg_read(kbdev,
|
||||
MMU_AS_REG(as_no,
|
||||
AS_FAULTADDRESS_LO),
|
||||
kctx);
|
||||
|
||||
/* record the fault status */
|
||||
as->fault_status = kbase_reg_read(kbdev,
|
||||
MMU_AS_REG(as_no,
|
||||
AS_FAULTSTATUS),
|
||||
kctx);
|
||||
|
||||
/* find the fault type */
|
||||
as->fault_type = (bf_bits & (1 << as_no)) ?
|
||||
KBASE_MMU_FAULT_TYPE_BUS :
|
||||
KBASE_MMU_FAULT_TYPE_PAGE;
|
||||
|
||||
|
||||
if (kbase_as_has_bus_fault(as)) {
|
||||
/* Mark bus fault as handled.
|
||||
* Note that a bus fault is processed first in case
|
||||
* where both a bus fault and page fault occur.
|
||||
*/
|
||||
bf_bits &= ~(1UL << as_no);
|
||||
|
||||
/* remove the queued BF (and PF) from the mask */
|
||||
new_mask &= ~(MMU_BUS_ERROR(as_no) |
|
||||
MMU_PAGE_FAULT(as_no));
|
||||
} else {
|
||||
/* Mark page fault as handled */
|
||||
pf_bits &= ~(1UL << as_no);
|
||||
|
||||
/* remove the queued PF from the mask */
|
||||
new_mask &= ~MMU_PAGE_FAULT(as_no);
|
||||
}
|
||||
|
||||
/* Process the interrupt for this address space */
|
||||
spin_lock_irqsave(&kbdev->js_data.runpool_irq.lock, flags);
|
||||
kbase_mmu_interrupt_process(kbdev, kctx, as);
|
||||
spin_unlock_irqrestore(&kbdev->js_data.runpool_irq.lock,
|
||||
flags);
|
||||
}
|
||||
|
||||
/* reenable interrupts */
|
||||
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
|
||||
tmp = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), NULL);
|
||||
new_mask |= tmp;
|
||||
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), new_mask, NULL);
|
||||
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
|
||||
}
|
||||
|
||||
void kbase_mmu_hw_configure(struct kbase_device *kbdev, struct kbase_as *as,
|
||||
struct kbase_context *kctx)
|
||||
{
|
||||
struct kbase_mmu_setup *current_setup = &as->current_setup;
|
||||
#if defined(CONFIG_MALI_MIPE_ENABLED) || \
|
||||
(defined(MALI_INCLUDE_TMIX) && \
|
||||
defined(CONFIG_MALI_COH_PAGES) && \
|
||||
defined(CONFIG_MALI_GPU_MMU_AARCH64))
|
||||
u32 transcfg = 0;
|
||||
#endif
|
||||
|
||||
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_LO),
|
||||
current_setup->transtab & 0xFFFFFFFFUL, kctx);
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_TRANSTAB_HI),
|
||||
(current_setup->transtab >> 32) & 0xFFFFFFFFUL, kctx);
|
||||
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_LO),
|
||||
current_setup->memattr & 0xFFFFFFFFUL, kctx);
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_MEMATTR_HI),
|
||||
(current_setup->memattr >> 32) & 0xFFFFFFFFUL, kctx);
|
||||
|
||||
#if defined(CONFIG_MALI_MIPE_ENABLED)
|
||||
kbase_tlstream_tl_attrib_as_config(as,
|
||||
current_setup->transtab,
|
||||
current_setup->memattr,
|
||||
transcfg);
|
||||
#endif
|
||||
|
||||
write_cmd(kbdev, as->number, AS_COMMAND_UPDATE, kctx);
|
||||
}
|
||||
|
||||
int kbase_mmu_hw_do_operation(struct kbase_device *kbdev, struct kbase_as *as,
|
||||
struct kbase_context *kctx, u64 vpfn, u32 nr, u32 op,
|
||||
unsigned int handling_irq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (op == AS_COMMAND_UNLOCK) {
|
||||
/* Unlock doesn't require a lock first */
|
||||
ret = write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx);
|
||||
} else {
|
||||
u64 lock_addr = lock_region(kbdev, vpfn, nr);
|
||||
|
||||
/* Lock the region that needs to be updated */
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_LO),
|
||||
lock_addr & 0xFFFFFFFFUL, kctx);
|
||||
kbase_reg_write(kbdev, MMU_AS_REG(as->number, AS_LOCKADDR_HI),
|
||||
(lock_addr >> 32) & 0xFFFFFFFFUL, kctx);
|
||||
write_cmd(kbdev, as->number, AS_COMMAND_LOCK, kctx);
|
||||
|
||||
/* Run the MMU operation */
|
||||
write_cmd(kbdev, as->number, op, kctx);
|
||||
|
||||
/* Wait for the flush to complete */
|
||||
ret = wait_ready(kbdev, as->number, kctx);
|
||||
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_9630)) {
|
||||
/* Issue an UNLOCK command to ensure that valid page
|
||||
tables are re-read by the GPU after an update.
|
||||
Note that, the FLUSH command should perform all the
|
||||
actions necessary, however the bus logs show that if
|
||||
multiple page faults occur within an 8 page region
|
||||
the MMU does not always re-read the updated page
|
||||
table entries for later faults or is only partially
|
||||
read, it subsequently raises the page fault IRQ for
|
||||
the same addresses, the unlock ensures that the MMU
|
||||
cache is flushed, so updates can be re-read. As the
|
||||
region is now unlocked we need to issue 2 UNLOCK
|
||||
commands in order to flush the MMU/uTLB,
|
||||
see PRLAM-8812.
|
||||
*/
|
||||
write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx);
|
||||
write_cmd(kbdev, as->number, AS_COMMAND_UNLOCK, kctx);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void kbase_mmu_hw_clear_fault(struct kbase_device *kbdev, struct kbase_as *as,
|
||||
struct kbase_context *kctx, enum kbase_mmu_fault_type type)
|
||||
{
|
||||
u32 pf_bf_mask;
|
||||
|
||||
/* Clear the page (and bus fault IRQ as well in case one occurred) */
|
||||
pf_bf_mask = MMU_PAGE_FAULT(as->number);
|
||||
if (type == KBASE_MMU_FAULT_TYPE_BUS ||
|
||||
type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED)
|
||||
pf_bf_mask |= MMU_BUS_ERROR(as->number);
|
||||
|
||||
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_CLEAR), pf_bf_mask, kctx);
|
||||
}
|
||||
|
||||
void kbase_mmu_hw_enable_fault(struct kbase_device *kbdev, struct kbase_as *as,
|
||||
struct kbase_context *kctx, enum kbase_mmu_fault_type type)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 irq_mask;
|
||||
|
||||
/* Enable the page fault IRQ (and bus fault IRQ as well in case one
|
||||
* occurred) */
|
||||
spin_lock_irqsave(&kbdev->mmu_mask_change, flags);
|
||||
|
||||
irq_mask = kbase_reg_read(kbdev, MMU_REG(MMU_IRQ_MASK), kctx) |
|
||||
MMU_PAGE_FAULT(as->number);
|
||||
|
||||
if (type == KBASE_MMU_FAULT_TYPE_BUS ||
|
||||
type == KBASE_MMU_FAULT_TYPE_BUS_UNEXPECTED)
|
||||
irq_mask |= MMU_BUS_ERROR(as->number);
|
||||
|
||||
kbase_reg_write(kbdev, MMU_REG(MMU_IRQ_MASK), irq_mask, kctx);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->mmu_mask_change, flags);
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 file for the direct implementation for MMU hardware access
|
||||
*
|
||||
* Direct MMU hardware interface
|
||||
*
|
||||
* This module provides the interface(s) that are required by the direct
|
||||
* register access implementation of the MMU hardware interface
|
||||
*/
|
||||
|
||||
#ifndef _MALI_KBASE_MMU_HW_DIRECT_H_
|
||||
#define _MALI_KBASE_MMU_HW_DIRECT_H_
|
||||
|
||||
#include <mali_kbase_defs.h>
|
||||
|
||||
/**
|
||||
* kbase_mmu_interrupt - Process an MMU interrupt.
|
||||
*
|
||||
* Process the MMU interrupt that was reported by the &kbase_device.
|
||||
*
|
||||
* @kbdev: kbase context to clear the fault from.
|
||||
* @irq_stat: Value of the MMU_IRQ_STATUS register
|
||||
*/
|
||||
void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat);
|
||||
|
||||
#endif /* _MALI_KBASE_MMU_HW_DIRECT_H_ */
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "Always on" power management policy
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
|
||||
static u64 always_on_get_core_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
return kbdev->gpu_props.props.raw_props.shader_present;
|
||||
}
|
||||
|
||||
static bool always_on_get_core_active(struct kbase_device *kbdev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void always_on_init(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
static void always_on_term(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* The struct kbase_pm_policy structure for the demand power policy.
|
||||
*
|
||||
* This is the static structure that defines the demand power policy's callback
|
||||
* and name.
|
||||
*/
|
||||
const struct kbase_pm_policy kbase_pm_always_on_policy_ops = {
|
||||
"always_on", /* name */
|
||||
always_on_init, /* init */
|
||||
always_on_term, /* term */
|
||||
always_on_get_core_mask, /* get_core_mask */
|
||||
always_on_get_core_active, /* get_core_active */
|
||||
0u, /* flags */
|
||||
KBASE_PM_POLICY_ID_ALWAYS_ON, /* id */
|
||||
};
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_always_on_policy_ops);
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "Always on" power management policy
|
||||
*/
|
||||
|
||||
#ifndef MALI_KBASE_PM_ALWAYS_ON_H
|
||||
#define MALI_KBASE_PM_ALWAYS_ON_H
|
||||
|
||||
/**
|
||||
* DOC:
|
||||
* The "Always on" power management policy has the following
|
||||
* characteristics:
|
||||
*
|
||||
* - When KBase indicates that the GPU will be powered up, but we don't yet
|
||||
* know which Job Chains are to be run:
|
||||
* All Shader Cores are powered up, regardless of whether or not they will
|
||||
* be needed later.
|
||||
*
|
||||
* - When KBase indicates that a set of Shader Cores are needed to submit the
|
||||
* currently queued Job Chains:
|
||||
* All Shader Cores are kept powered, regardless of whether or not they will
|
||||
* be needed
|
||||
*
|
||||
* - When KBase indicates that the GPU need not be powered:
|
||||
* The Shader Cores are kept powered, regardless of whether or not they will
|
||||
* be needed. The GPU itself is also kept powered, even though it is not
|
||||
* needed.
|
||||
*
|
||||
* This policy is automatically overridden during system suspend: the desired
|
||||
* core state is ignored, and the cores are forced off regardless of what the
|
||||
* policy requests. After resuming from suspend, new changes to the desired
|
||||
* core state made by the policy are honored.
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* - KBase indicates the GPU will be powered up when it has a User Process that
|
||||
* has just started to submit Job Chains.
|
||||
*
|
||||
* - KBase indicates the GPU need not be powered when all the Job Chains from
|
||||
* User Processes have finished, and it is waiting for a User Process to
|
||||
* submit some more Job Chains.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct kbasep_pm_policy_always_on - Private struct for policy instance data
|
||||
* @dummy: unused dummy variable
|
||||
*
|
||||
* This contains data that is private to the particular power policy that is
|
||||
* active.
|
||||
*/
|
||||
struct kbasep_pm_policy_always_on {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
extern const struct kbase_pm_policy kbase_pm_always_on_policy_ops;
|
||||
|
||||
#endif /* MALI_KBASE_PM_ALWAYS_ON_H */
|
||||
|
||||
398
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_backend.c
Normal file
398
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_backend.c
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* GPU backend implementation of base kernel power management APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
#ifdef CONFIG_MALI_PLATFORM_DEVICETREE
|
||||
#include <linux/pm_runtime.h>
|
||||
#endif /* CONFIG_MALI_PLATFORM_DEVICETREE */
|
||||
|
||||
#include <mali_kbase_pm.h>
|
||||
#include <backend/gpu/mali_kbase_jm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
void kbase_pm_register_access_enable(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_pm_callback_conf *callbacks;
|
||||
|
||||
#ifdef CONFIG_MALI_PLATFORM_DEVICETREE
|
||||
pm_runtime_enable(kbdev->dev);
|
||||
#endif /* CONFIG_MALI_PLATFORM_DEVICETREE */
|
||||
callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS;
|
||||
|
||||
if (callbacks)
|
||||
callbacks->power_on_callback(kbdev);
|
||||
|
||||
kbdev->pm.backend.gpu_powered = true;
|
||||
}
|
||||
|
||||
void kbase_pm_register_access_disable(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_pm_callback_conf *callbacks;
|
||||
|
||||
callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS;
|
||||
|
||||
if (callbacks)
|
||||
callbacks->power_off_callback(kbdev);
|
||||
|
||||
kbdev->pm.backend.gpu_powered = false;
|
||||
#ifdef CONFIG_MALI_PLATFORM_DEVICETREE
|
||||
pm_runtime_disable(kbdev->dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
int kbase_hwaccess_pm_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct kbase_pm_callback_conf *callbacks;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
mutex_init(&kbdev->pm.lock);
|
||||
|
||||
kbdev->pm.backend.gpu_powered = false;
|
||||
kbdev->pm.suspending = false;
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
init_waitqueue_head(&kbdev->pm.suspending_wait);
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
kbdev->pm.backend.driver_ready_for_irqs = false;
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
kbdev->pm.backend.gpu_in_desired_state = true;
|
||||
init_waitqueue_head(&kbdev->pm.backend.gpu_in_desired_state_wait);
|
||||
|
||||
callbacks = (struct kbase_pm_callback_conf *)POWER_MANAGEMENT_CALLBACKS;
|
||||
if (callbacks) {
|
||||
kbdev->pm.backend.callback_power_on =
|
||||
callbacks->power_on_callback;
|
||||
kbdev->pm.backend.callback_power_off =
|
||||
callbacks->power_off_callback;
|
||||
kbdev->pm.backend.callback_power_suspend =
|
||||
callbacks->power_suspend_callback;
|
||||
kbdev->pm.backend.callback_power_resume =
|
||||
callbacks->power_resume_callback;
|
||||
kbdev->pm.callback_power_runtime_init =
|
||||
callbacks->power_runtime_init_callback;
|
||||
kbdev->pm.callback_power_runtime_term =
|
||||
callbacks->power_runtime_term_callback;
|
||||
kbdev->pm.backend.callback_power_runtime_on =
|
||||
callbacks->power_runtime_on_callback;
|
||||
kbdev->pm.backend.callback_power_runtime_off =
|
||||
callbacks->power_runtime_off_callback;
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
kbdev->pm.backend.callback_power_dvfs_on =
|
||||
callbacks->power_dvfs_on_callback;
|
||||
kbdev->pm.backend.callback_power_change_dvfs_level =
|
||||
callbacks->power_change_dvfs_level_callback;
|
||||
} else {
|
||||
kbdev->pm.backend.callback_power_on = NULL;
|
||||
kbdev->pm.backend.callback_power_off = NULL;
|
||||
kbdev->pm.backend.callback_power_suspend = NULL;
|
||||
kbdev->pm.backend.callback_power_resume = NULL;
|
||||
kbdev->pm.callback_power_runtime_init = NULL;
|
||||
kbdev->pm.callback_power_runtime_term = NULL;
|
||||
kbdev->pm.backend.callback_power_runtime_on = NULL;
|
||||
kbdev->pm.backend.callback_power_runtime_off = NULL;
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
kbdev->pm.backend.callback_power_dvfs_on = NULL;
|
||||
kbdev->pm.backend.callback_power_change_dvfs_level = NULL;
|
||||
}
|
||||
|
||||
/* Initialise the metrics subsystem */
|
||||
ret = kbasep_pm_metrics_init(kbdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
init_waitqueue_head(&kbdev->pm.backend.l2_powered_wait);
|
||||
kbdev->pm.backend.l2_powered = 0;
|
||||
|
||||
init_waitqueue_head(&kbdev->pm.backend.reset_done_wait);
|
||||
kbdev->pm.backend.reset_done = false;
|
||||
|
||||
init_waitqueue_head(&kbdev->pm.zero_active_count_wait);
|
||||
kbdev->pm.active_count = 0;
|
||||
|
||||
spin_lock_init(&kbdev->pm.power_change_lock);
|
||||
spin_lock_init(&kbdev->pm.backend.gpu_cycle_counter_requests_lock);
|
||||
spin_lock_init(&kbdev->pm.backend.gpu_powered_lock);
|
||||
|
||||
if (kbase_pm_ca_init(kbdev) != 0)
|
||||
goto workq_fail;
|
||||
|
||||
if (kbase_pm_policy_init(kbdev) != 0)
|
||||
goto pm_policy_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
pm_policy_fail:
|
||||
kbase_pm_ca_term(kbdev);
|
||||
workq_fail:
|
||||
kbasep_pm_metrics_term(kbdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void kbase_pm_do_poweron(struct kbase_device *kbdev, bool is_resume)
|
||||
{
|
||||
lockdep_assert_held(&kbdev->pm.lock);
|
||||
|
||||
/* Turn clocks and interrupts on - no-op if we haven't done a previous
|
||||
* kbase_pm_clock_off() */
|
||||
kbase_pm_clock_on(kbdev, is_resume);
|
||||
|
||||
/* Update core status as required by the policy */
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_START);
|
||||
kbase_pm_update_cores_state(kbdev);
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_DO_POWERON_END);
|
||||
|
||||
/* NOTE: We don't wait to reach the desired state, since running atoms
|
||||
* will wait for that state to be reached anyway */
|
||||
}
|
||||
|
||||
bool kbase_pm_do_poweroff(struct kbase_device *kbdev, bool is_suspend)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool cores_are_available;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.lock);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
/* Force all cores off */
|
||||
kbdev->pm.backend.desired_shader_state = 0;
|
||||
|
||||
/* Force all cores to be unavailable, in the situation where
|
||||
* transitions are in progress for some cores but not others,
|
||||
* and kbase_pm_check_transitions_nolock can not immediately
|
||||
* power off the cores */
|
||||
kbdev->shader_available_bitmap = 0;
|
||||
kbdev->tiler_available_bitmap = 0;
|
||||
kbdev->l2_available_bitmap = 0;
|
||||
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_START);
|
||||
cores_are_available = kbase_pm_check_transitions_nolock(kbdev);
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_DO_POWEROFF_END);
|
||||
/* Don't need 'cores_are_available', because we don't return anything */
|
||||
CSTD_UNUSED(cores_are_available);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
/* NOTE: We won't wait to reach the core's desired state, even if we're
|
||||
* powering off the GPU itself too. It's safe to cut the power whilst
|
||||
* they're transitioning to off, because the cores should be idle and
|
||||
* all cache flushes should already have occurred */
|
||||
|
||||
/* Consume any change-state events */
|
||||
kbase_timeline_pm_check_handle_event(kbdev,
|
||||
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
|
||||
/* Disable interrupts and turn the clock off */
|
||||
return kbase_pm_clock_off(kbdev, is_suspend);
|
||||
}
|
||||
|
||||
int kbase_hwaccess_pm_powerup(struct kbase_device *kbdev,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
unsigned long irq_flags;
|
||||
int ret;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
/* while the GPU initialization, vendor desired gpu log will be out by set_power_dbg(FALSE) calls */
|
||||
if(kbdev->vendor_callbacks->set_poweron_dbg)
|
||||
kbdev->vendor_callbacks->set_poweron_dbg(false);
|
||||
|
||||
/* A suspend won't happen during startup/insmod */
|
||||
KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev));
|
||||
|
||||
/* Power up the GPU, don't enable IRQs as we are not ready to receive
|
||||
* them. */
|
||||
ret = kbase_pm_init_hw(kbdev, flags);
|
||||
if (ret) {
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
kbasep_pm_read_present_cores(kbdev);
|
||||
|
||||
kbdev->pm.debug_core_mask =
|
||||
kbdev->gpu_props.props.raw_props.shader_present;
|
||||
|
||||
/* Pretend the GPU is active to prevent a power policy turning the GPU
|
||||
* cores off */
|
||||
kbdev->pm.active_count = 1;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
|
||||
irq_flags);
|
||||
/* Ensure cycle counter is off */
|
||||
kbdev->pm.backend.gpu_cycle_counter_requests = 0;
|
||||
spin_unlock_irqrestore(
|
||||
&kbdev->pm.backend.gpu_cycle_counter_requests_lock,
|
||||
irq_flags);
|
||||
|
||||
/* We are ready to receive IRQ's now as power policy is set up, so
|
||||
* enable them now. */
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
spin_lock_irqsave(&kbdev->pm.backend.gpu_powered_lock, irq_flags);
|
||||
kbdev->pm.backend.driver_ready_for_irqs = true;
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.gpu_powered_lock, irq_flags);
|
||||
#endif
|
||||
kbase_pm_enable_interrupts(kbdev);
|
||||
|
||||
/* Turn on the GPU and any cores needed by the policy */
|
||||
kbase_pm_do_poweron(kbdev, false);
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
|
||||
#ifdef MALI_SEC_HWCNT
|
||||
if (kbdev->hwcnt.is_hwcnt_attach == false)
|
||||
if (kbdev->vendor_callbacks->hwcnt_attach)
|
||||
kbdev->vendor_callbacks->hwcnt_attach(kbdev);
|
||||
#endif
|
||||
|
||||
/* Idle the GPU and/or cores, if the policy wants it to */
|
||||
kbase_pm_context_idle(kbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbase_hwaccess_pm_halt(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
kbase_pm_cancel_deferred_poweroff(kbdev);
|
||||
if (!kbase_pm_do_poweroff(kbdev, false)) {
|
||||
/* Page/bus faults are pending, must drop pm.lock to process.
|
||||
* Interrupts are disabled so no more faults should be
|
||||
* generated at this point */
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
kbase_flush_mmu_wqs(kbdev);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
WARN_ON(!kbase_pm_do_poweroff(kbdev, false));
|
||||
}
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_hwaccess_pm_halt);
|
||||
|
||||
void kbase_hwaccess_pm_term(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.active_count == 0);
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_cycle_counter_requests == 0);
|
||||
|
||||
/* Free any resources the policy allocated */
|
||||
kbase_pm_policy_term(kbdev);
|
||||
kbase_pm_ca_term(kbdev);
|
||||
|
||||
/* Shut down the metrics subsystem */
|
||||
kbasep_pm_metrics_term(kbdev);
|
||||
}
|
||||
|
||||
void kbase_pm_power_changed(struct kbase_device *kbdev)
|
||||
{
|
||||
bool cores_are_available;
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_START);
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
cores_are_available = kbase_pm_check_transitions_nolock(kbdev);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_GPU_INTERRUPT_END);
|
||||
|
||||
if (cores_are_available) {
|
||||
/* Log timelining information that a change in state has
|
||||
* completed */
|
||||
kbase_timeline_pm_handle_event(kbdev,
|
||||
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
|
||||
|
||||
spin_lock_irqsave(&kbdev->js_data.runpool_irq.lock, flags);
|
||||
kbase_gpu_slot_update(kbdev);
|
||||
spin_unlock_irqrestore(&kbdev->js_data.runpool_irq.lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_pm_set_debug_core_mask(struct kbase_device *kbdev, u64 new_core_mask)
|
||||
{
|
||||
kbdev->pm.debug_core_mask = new_core_mask;
|
||||
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
}
|
||||
|
||||
void kbase_hwaccess_pm_gpu_active(struct kbase_device *kbdev)
|
||||
{
|
||||
kbase_pm_update_active(kbdev);
|
||||
}
|
||||
|
||||
void kbase_hwaccess_pm_gpu_idle(struct kbase_device *kbdev)
|
||||
{
|
||||
kbase_pm_update_active(kbdev);
|
||||
}
|
||||
|
||||
void kbase_hwaccess_pm_suspend(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
|
||||
/* Force power off the GPU and all cores (regardless of policy), only
|
||||
* after the PM active count reaches zero (otherwise, we risk turning it
|
||||
* off prematurely) */
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
kbase_pm_cancel_deferred_poweroff(kbdev);
|
||||
if (!kbase_pm_do_poweroff(kbdev, true)) {
|
||||
/* Page/bus faults are pending, must drop pm.lock to process.
|
||||
* Interrupts are disabled so no more faults should be
|
||||
* generated at this point */
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
kbase_flush_mmu_wqs(kbdev);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
WARN_ON(!kbase_pm_do_poweroff(kbdev, false));
|
||||
}
|
||||
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
}
|
||||
|
||||
void kbase_hwaccess_pm_resume(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
kbdev->pm.suspending = false;
|
||||
kbase_pm_do_poweron(kbdev, true);
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
wake_up(&kbdev->pm.suspending_wait);
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
}
|
||||
182
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_ca.c
Normal file
182
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_ca.c
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel core availability APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
static const struct kbase_pm_ca_policy *const policy_list[] = {
|
||||
&kbase_pm_ca_fixed_policy_ops,
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
&kbase_pm_ca_random_policy_ops
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* POLICY_COUNT - The number of policies available in the system.
|
||||
*
|
||||
* This is derived from the number of functions listed in policy_list.
|
||||
*/
|
||||
#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list))
|
||||
|
||||
int kbase_pm_ca_init(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
kbdev->pm.backend.ca_current_policy = policy_list[0];
|
||||
|
||||
kbdev->pm.backend.ca_current_policy->init(kbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbase_pm_ca_term(struct kbase_device *kbdev)
|
||||
{
|
||||
kbdev->pm.backend.ca_current_policy->term(kbdev);
|
||||
}
|
||||
|
||||
int kbase_pm_ca_list_policies(const struct kbase_pm_ca_policy * const **list)
|
||||
{
|
||||
if (!list)
|
||||
return POLICY_COUNT;
|
||||
|
||||
*list = policy_list;
|
||||
|
||||
return POLICY_COUNT;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_ca_list_policies);
|
||||
|
||||
const struct kbase_pm_ca_policy
|
||||
*kbase_pm_ca_get_policy(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
return kbdev->pm.backend.ca_current_policy;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_ca_get_policy);
|
||||
|
||||
void kbase_pm_ca_set_policy(struct kbase_device *kbdev,
|
||||
const struct kbase_pm_ca_policy *new_policy)
|
||||
{
|
||||
const struct kbase_pm_ca_policy *old_policy;
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(new_policy != NULL);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, PM_CA_SET_POLICY, NULL, NULL, 0u,
|
||||
new_policy->id);
|
||||
|
||||
/* During a policy change we pretend the GPU is active */
|
||||
/* A suspend won't happen here, because we're in a syscall from a
|
||||
* userspace thread */
|
||||
kbase_pm_context_active(kbdev);
|
||||
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
|
||||
/* Remove the policy to prevent IRQ handlers from working on it */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
old_policy = kbdev->pm.backend.ca_current_policy;
|
||||
kbdev->pm.backend.ca_current_policy = NULL;
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
if (old_policy->term)
|
||||
old_policy->term(kbdev);
|
||||
|
||||
if (new_policy->init)
|
||||
new_policy->init(kbdev);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
kbdev->pm.backend.ca_current_policy = new_policy;
|
||||
|
||||
/* If any core power state changes were previously attempted, but
|
||||
* couldn't be made because the policy was changing (current_policy was
|
||||
* NULL), then re-try them here. */
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
|
||||
kbdev->pm.backend.ca_current_policy->update_core_status(kbdev,
|
||||
kbdev->shader_ready_bitmap,
|
||||
kbdev->shader_transitioning_bitmap);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
|
||||
/* Now the policy change is finished, we release our fake context active
|
||||
* reference */
|
||||
kbase_pm_context_idle(kbdev);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_ca_set_policy);
|
||||
|
||||
u64 kbase_pm_ca_get_core_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
lockdep_assert_held(&kbdev->pm.power_change_lock);
|
||||
|
||||
/* All cores must be enabled when instrumentation is in use */
|
||||
if (kbdev->pm.backend.instr_enabled)
|
||||
return kbdev->gpu_props.props.raw_props.shader_present &
|
||||
kbdev->pm.debug_core_mask;
|
||||
|
||||
if (kbdev->pm.backend.ca_current_policy == NULL)
|
||||
return kbdev->gpu_props.props.raw_props.shader_present &
|
||||
kbdev->pm.debug_core_mask;
|
||||
|
||||
return kbdev->pm.backend.ca_current_policy->get_core_mask(kbdev) &
|
||||
kbdev->pm.debug_core_mask;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_ca_get_core_mask);
|
||||
|
||||
void kbase_pm_ca_update_core_status(struct kbase_device *kbdev, u64 cores_ready,
|
||||
u64 cores_transitioning)
|
||||
{
|
||||
lockdep_assert_held(&kbdev->pm.power_change_lock);
|
||||
|
||||
if (kbdev->pm.backend.ca_current_policy != NULL)
|
||||
kbdev->pm.backend.ca_current_policy->update_core_status(kbdev,
|
||||
cores_ready,
|
||||
cores_transitioning);
|
||||
}
|
||||
|
||||
void kbase_pm_ca_instr_enable(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
kbdev->pm.backend.instr_enabled = true;
|
||||
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
void kbase_pm_ca_instr_disable(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
kbdev->pm.backend.instr_enabled = false;
|
||||
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
92
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_ca.h
Normal file
92
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_ca.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel core availability APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_PM_CA_H_
|
||||
#define _KBASE_PM_CA_H_
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_init - Initialize core availability framework
|
||||
*
|
||||
* Must be called before calling any other core availability function
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Return: 0 if the core availability framework was successfully initialized,
|
||||
* -errno otherwise
|
||||
*/
|
||||
int kbase_pm_ca_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_term - Terminate core availability framework
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_ca_term(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_get_core_mask - Get currently available shaders core mask
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Returns a mask of the currently available shader cores.
|
||||
* Calls into the core availability policy
|
||||
*
|
||||
* Return: The bit mask of available cores
|
||||
*/
|
||||
u64 kbase_pm_ca_get_core_mask(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_update_core_status - Update core status
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be
|
||||
* a valid pointer)
|
||||
* @cores_ready: The bit mask of cores ready for job submission
|
||||
* @cores_transitioning: The bit mask of cores that are transitioning power
|
||||
* state
|
||||
*
|
||||
* Update core availability policy with current core power status
|
||||
*
|
||||
* Calls into the core availability policy
|
||||
*/
|
||||
void kbase_pm_ca_update_core_status(struct kbase_device *kbdev, u64 cores_ready,
|
||||
u64 cores_transitioning);
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_instr_enable - Enable override for instrumentation
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* This overrides the output of the core availability policy, ensuring that all
|
||||
* cores are available
|
||||
*/
|
||||
void kbase_pm_ca_instr_enable(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_ca_instr_disable - Disable override for instrumentation
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* This disables any previously enabled override, and resumes normal policy
|
||||
* functionality
|
||||
*/
|
||||
void kbase_pm_ca_instr_disable(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_PM_CA_H_ */
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A power policy implementing fixed core availability
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
|
||||
static void fixed_init(struct kbase_device *kbdev)
|
||||
{
|
||||
kbdev->pm.backend.ca_in_transition = false;
|
||||
}
|
||||
|
||||
static void fixed_term(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
static u64 fixed_get_core_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
return kbdev->gpu_props.props.raw_props.shader_present;
|
||||
}
|
||||
|
||||
static void fixed_update_core_status(struct kbase_device *kbdev,
|
||||
u64 cores_ready,
|
||||
u64 cores_transitioning)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
CSTD_UNUSED(cores_ready);
|
||||
CSTD_UNUSED(cores_transitioning);
|
||||
}
|
||||
|
||||
/*
|
||||
* The struct kbase_pm_policy structure for the fixed power policy.
|
||||
*
|
||||
* This is the static structure that defines the fixed power policy's callback
|
||||
* and name.
|
||||
*/
|
||||
const struct kbase_pm_ca_policy kbase_pm_ca_fixed_policy_ops = {
|
||||
"fixed", /* name */
|
||||
fixed_init, /* init */
|
||||
fixed_term, /* term */
|
||||
fixed_get_core_mask, /* get_core_mask */
|
||||
fixed_update_core_status, /* update_core_status */
|
||||
0u, /* flags */
|
||||
KBASE_PM_CA_POLICY_ID_FIXED, /* id */
|
||||
};
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_ca_fixed_policy_ops);
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A power policy implementing fixed core availability
|
||||
*/
|
||||
|
||||
#ifndef MALI_KBASE_PM_CA_FIXED_H
|
||||
#define MALI_KBASE_PM_CA_FIXED_H
|
||||
|
||||
/**
|
||||
* struct kbasep_pm_ca_policy_fixed - Private structure for policy instance data
|
||||
*
|
||||
* @dummy: Dummy member - no state is needed
|
||||
*
|
||||
* This contains data that is private to the particular power policy that is
|
||||
* active.
|
||||
*/
|
||||
struct kbasep_pm_ca_policy_fixed {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
extern const struct kbase_pm_ca_policy kbase_pm_ca_fixed_policy_ops;
|
||||
|
||||
#endif /* MALI_KBASE_PM_CA_FIXED_H */
|
||||
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "Coarse Demand" power management policy
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
|
||||
static u64 coarse_demand_get_core_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
if (kbdev->pm.active_count == 0)
|
||||
return 0;
|
||||
|
||||
return kbdev->gpu_props.props.raw_props.shader_present;
|
||||
}
|
||||
|
||||
static bool coarse_demand_get_core_active(struct kbase_device *kbdev)
|
||||
{
|
||||
if (0 == kbdev->pm.active_count && !(kbdev->shader_needed_bitmap |
|
||||
kbdev->shader_inuse_bitmap))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void coarse_demand_init(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
static void coarse_demand_term(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
/* The struct kbase_pm_policy structure for the demand power policy.
|
||||
*
|
||||
* This is the static structure that defines the demand power policy's callback
|
||||
* and name.
|
||||
*/
|
||||
const struct kbase_pm_policy kbase_pm_coarse_demand_policy_ops = {
|
||||
"coarse_demand", /* name */
|
||||
coarse_demand_init, /* init */
|
||||
coarse_demand_term, /* term */
|
||||
coarse_demand_get_core_mask, /* get_core_mask */
|
||||
coarse_demand_get_core_active, /* get_core_active */
|
||||
0u, /* flags */
|
||||
KBASE_PM_POLICY_ID_COARSE_DEMAND, /* id */
|
||||
};
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_coarse_demand_policy_ops);
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* "Coarse Demand" power management policy
|
||||
*/
|
||||
|
||||
#ifndef MALI_KBASE_PM_COARSE_DEMAND_H
|
||||
#define MALI_KBASE_PM_COARSE_DEMAND_H
|
||||
|
||||
/**
|
||||
* DOC:
|
||||
* The "Coarse" demand power management policy has the following
|
||||
* characteristics:
|
||||
* - When KBase indicates that the GPU will be powered up, but we don't yet
|
||||
* know which Job Chains are to be run:
|
||||
* - All Shader Cores are powered up, regardless of whether or not they will
|
||||
* be needed later.
|
||||
* - When KBase indicates that a set of Shader Cores are needed to submit the
|
||||
* currently queued Job Chains:
|
||||
* - All Shader Cores are kept powered, regardless of whether or not they will
|
||||
* be needed
|
||||
* - When KBase indicates that the GPU need not be powered:
|
||||
* - The Shader Cores are powered off, and the GPU itself is powered off too.
|
||||
*
|
||||
* @note:
|
||||
* - KBase indicates the GPU will be powered up when it has a User Process that
|
||||
* has just started to submit Job Chains.
|
||||
* - KBase indicates the GPU need not be powered when all the Job Chains from
|
||||
* User Processes have finished, and it is waiting for a User Process to
|
||||
* submit some more Job Chains.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct kbasep_pm_policy_coarse_demand - Private structure for coarse demand
|
||||
* policy
|
||||
*
|
||||
* This contains data that is private to the coarse demand power policy.
|
||||
*
|
||||
* @dummy: Dummy member - no state needed
|
||||
*/
|
||||
struct kbasep_pm_policy_coarse_demand {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
extern const struct kbase_pm_policy kbase_pm_coarse_demand_policy_ops;
|
||||
|
||||
#endif /* MALI_KBASE_PM_COARSE_DEMAND_H */
|
||||
485
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_defs.h
Normal file
485
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_defs.h
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Backend-specific Power Manager definitions
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_PM_HWACCESS_DEFS_H_
|
||||
#define _KBASE_PM_HWACCESS_DEFS_H_
|
||||
|
||||
#include "mali_kbase_pm_ca_fixed.h"
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
#include "mali_kbase_pm_ca_random.h"
|
||||
#endif
|
||||
|
||||
#include "mali_kbase_pm_always_on.h"
|
||||
#include "mali_kbase_pm_coarse_demand.h"
|
||||
#include "mali_kbase_pm_demand.h"
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
#include "mali_kbase_pm_demand_always_powered.h"
|
||||
#include "mali_kbase_pm_fast_start.h"
|
||||
#endif
|
||||
|
||||
/* Forward definition - see mali_kbase.h */
|
||||
struct kbase_device;
|
||||
struct kbase_jd_atom;
|
||||
|
||||
/**
|
||||
* enum kbase_pm_core_type - The types of core in a GPU.
|
||||
*
|
||||
* These enumerated values are used in calls to
|
||||
* - kbase_pm_get_present_cores()
|
||||
* - kbase_pm_get_active_cores()
|
||||
* - kbase_pm_get_trans_cores()
|
||||
* - kbase_pm_get_ready_cores().
|
||||
*
|
||||
* They specify which type of core should be acted on. These values are set in
|
||||
* a manner that allows core_type_to_reg() function to be simpler and more
|
||||
* efficient.
|
||||
*
|
||||
* @KBASE_PM_CORE_L2: The L2 cache
|
||||
* @KBASE_PM_CORE_SHADER: Shader cores
|
||||
* @KBASE_PM_CORE_TILER: Tiler cores
|
||||
*/
|
||||
enum kbase_pm_core_type {
|
||||
KBASE_PM_CORE_L2 = L2_PRESENT_LO,
|
||||
KBASE_PM_CORE_SHADER = SHADER_PRESENT_LO,
|
||||
KBASE_PM_CORE_TILER = TILER_PRESENT_LO
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kbasep_pm_metrics_data - Metrics data collected for use by the power
|
||||
* management framework.
|
||||
*
|
||||
* @time_period_start: time at which busy/idle measurements started
|
||||
* @time_busy: number of ns the GPU was busy executing jobs since the
|
||||
* @time_period_start timestamp.
|
||||
* @time_idle: number of ns since time_period_start the GPU was not executing
|
||||
* jobs since the @time_period_start timestamp.
|
||||
* @prev_busy: busy time in ns of previous time period.
|
||||
* Updated when metrics are reset.
|
||||
* @prev_idle: idle time in ns of previous time period
|
||||
* Updated when metrics are reset.
|
||||
* @gpu_active: true when the GPU is executing jobs. false when
|
||||
* not. Updated when the job scheduler informs us a job in submitted
|
||||
* or removed from a GPU slot.
|
||||
* @busy_cl: number of ns the GPU was busy executing CL jobs. Note that
|
||||
* if two CL jobs were active for 400ns, this value would be updated
|
||||
* with 800.
|
||||
* @busy_gl: number of ns the GPU was busy executing GL jobs. Note that
|
||||
* if two GL jobs were active for 400ns, this value would be updated
|
||||
* with 800.
|
||||
* @active_cl_ctx: number of CL jobs active on the GPU. Array is per-device.
|
||||
* @active_gl_ctx: number of GL jobs active on the GPU. Array is per-slot. As
|
||||
* GL jobs never run on slot 2 this slot is not recorded.
|
||||
* @lock: spinlock protecting the kbasep_pm_metrics_data structure
|
||||
* @timer: timer to regularly make DVFS decisions based on the power
|
||||
* management metrics.
|
||||
* @timer_active: boolean indicating @timer is running
|
||||
* @platform_data: pointer to data controlled by platform specific code
|
||||
* @kbdev: pointer to kbase device for which metrics are collected
|
||||
*
|
||||
*/
|
||||
struct kbasep_pm_metrics_data {
|
||||
ktime_t time_period_start;
|
||||
u32 time_busy;
|
||||
u32 time_idle;
|
||||
u32 prev_busy;
|
||||
u32 prev_idle;
|
||||
bool gpu_active;
|
||||
u32 busy_cl[2];
|
||||
u32 busy_gl;
|
||||
u32 active_cl_ctx[2];
|
||||
u32 active_gl_ctx[2]; /* GL jobs can only run on 2 of the 3 job slots */
|
||||
spinlock_t lock;
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
/* #ifdef CONFIG_MALI_MIDGARD_DVFS */
|
||||
struct hrtimer timer;
|
||||
bool timer_active;
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
struct delayed_work work;
|
||||
/* #endif */
|
||||
|
||||
void *platform_data;
|
||||
struct kbase_device *kbdev;
|
||||
#ifdef MALI_SEC_CL_BOOST
|
||||
atomic_t time_compute_jobs, time_vertex_jobs, time_fragment_jobs;
|
||||
#endif
|
||||
};
|
||||
|
||||
union kbase_pm_policy_data {
|
||||
struct kbasep_pm_policy_always_on always_on;
|
||||
struct kbasep_pm_policy_coarse_demand coarse_demand;
|
||||
struct kbasep_pm_policy_demand demand;
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
struct kbasep_pm_policy_demand_always_powered demand_always_powered;
|
||||
struct kbasep_pm_policy_fast_start fast_start;
|
||||
#endif
|
||||
};
|
||||
|
||||
union kbase_pm_ca_policy_data {
|
||||
struct kbasep_pm_ca_policy_fixed fixed;
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
struct kbasep_pm_ca_policy_random random;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kbase_pm_backend_data - Data stored per device for power management.
|
||||
*
|
||||
* This structure contains data for the power management framework. There is one
|
||||
* instance of this structure per device in the system.
|
||||
*
|
||||
* @ca_current_policy: The policy that is currently actively controlling core
|
||||
* availability.
|
||||
* @pm_current_policy: The policy that is currently actively controlling the
|
||||
* power state.
|
||||
* @ca_policy_data: Private data for current CA policy
|
||||
* @pm_policy_data: Private data for current PM policy
|
||||
* @ca_in_transition: Flag indicating when core availability policy is
|
||||
* transitioning cores. The core availability policy must
|
||||
* set this when a change in core availability is occurring.
|
||||
* power_change_lock must be held when accessing this.
|
||||
* @reset_done: Flag when a reset is complete
|
||||
* @reset_done_wait: Wait queue to wait for changes to @reset_done
|
||||
* @l2_powered_wait: Wait queue for whether the l2 cache has been powered as
|
||||
* requested
|
||||
* @l2_powered: State indicating whether all the l2 caches are powered.
|
||||
* Non-zero indicates they're *all* powered
|
||||
* Zero indicates that some (or all) are not powered
|
||||
* @gpu_cycle_counter_requests: The reference count of active gpu cycle counter
|
||||
* users
|
||||
* @gpu_cycle_counter_requests_lock: Lock to protect @gpu_cycle_counter_requests
|
||||
* @desired_shader_state: A bit mask identifying the shader cores that the
|
||||
* power policy would like to be on. The current state
|
||||
* of the cores may be different, but there should be
|
||||
* transitions in progress that will eventually achieve
|
||||
* this state (assuming that the policy doesn't change
|
||||
* its mind in the mean time).
|
||||
* @powering_on_shader_state: A bit mask indicating which shader cores are
|
||||
* currently in a power-on transition
|
||||
* @desired_tiler_state: A bit mask identifying the tiler cores that the power
|
||||
* policy would like to be on. See @desired_shader_state
|
||||
* @powering_on_tiler_state: A bit mask indicating which tiler core are
|
||||
* currently in a power-on transition
|
||||
* @powering_on_l2_state: A bit mask indicating which l2-caches are currently
|
||||
* in a power-on transition
|
||||
* @gpu_in_desired_state: This flag is set if the GPU is powered as requested
|
||||
* by the desired_xxx_state variables
|
||||
* @gpu_in_desired_state_wait: Wait queue set when @gpu_in_desired_state != 0
|
||||
* @gpu_powered: Set to true when the GPU is powered and register
|
||||
* accesses are possible, false otherwise
|
||||
* @instr_enabled: Set to true when instrumentation is enabled,
|
||||
* false otherwise
|
||||
* @cg1_disabled: Set if the policy wants to keep the second core group
|
||||
* powered off
|
||||
* @driver_ready_for_irqs: Debug state indicating whether sufficient
|
||||
* initialization of the driver has occurred to handle
|
||||
* IRQs
|
||||
* @gpu_powered_lock: Spinlock that must be held when writing @gpu_powered or
|
||||
* accessing @driver_ready_for_irqs
|
||||
* @metrics: Structure to hold metrics for the GPU
|
||||
* @gpu_poweroff_pending: number of poweroff timer ticks until the GPU is
|
||||
* powered off
|
||||
* @shader_poweroff_pending_time: number of poweroff timer ticks until shaders
|
||||
* are powered off
|
||||
* @gpu_poweroff_timer: Timer for powering off GPU
|
||||
* @gpu_poweroff_wq: Workqueue to power off GPU on when timer fires
|
||||
* @gpu_poweroff_work: Workitem used on @gpu_poweroff_wq
|
||||
* @shader_poweroff_pending: Bit mask of shaders to be powered off on next
|
||||
* timer callback
|
||||
* @poweroff_timer_needed: true if the poweroff timer is currently running,
|
||||
* false otherwise
|
||||
* @callback_power_on: Callback when the GPU needs to be turned on. See
|
||||
* &struct kbase_pm_callback_conf
|
||||
* @callback_power_off: Callback when the GPU may be turned off. See
|
||||
* &struct kbase_pm_callback_conf
|
||||
* @callback_power_suspend: Callback when a suspend occurs and the GPU needs to
|
||||
* be turned off. See &struct kbase_pm_callback_conf
|
||||
* @callback_power_resume: Callback when a resume occurs and the GPU needs to
|
||||
* be turned on. See &struct kbase_pm_callback_conf
|
||||
* @callback_power_runtime_on: Callback when the GPU needs to be turned on. See
|
||||
* &struct kbase_pm_callback_conf
|
||||
* @callback_power_runtime_off: Callback when the GPU may be turned off. See
|
||||
* &struct kbase_pm_callback_conf
|
||||
* @callback_cci_snoop_ctrl: Callback when the GPU L2 power may transition.
|
||||
* If enable is set then snoops should be enabled
|
||||
* otherwise snoops should be disabled
|
||||
*
|
||||
* Note:
|
||||
* During an IRQ, @ca_current_policy or @pm_current_policy can be NULL when the
|
||||
* policy is being changed with kbase_pm_ca_set_policy() or
|
||||
* kbase_pm_set_policy(). The change is protected under
|
||||
* kbase_device.pm.power_change_lock. Direct access to this
|
||||
* from IRQ context must therefore check for NULL. If NULL, then
|
||||
* kbase_pm_ca_set_policy() or kbase_pm_set_policy() will re-issue the policy
|
||||
* functions that would have been done under IRQ.
|
||||
*/
|
||||
struct kbase_pm_backend_data {
|
||||
const struct kbase_pm_ca_policy *ca_current_policy;
|
||||
const struct kbase_pm_policy *pm_current_policy;
|
||||
union kbase_pm_ca_policy_data ca_policy_data;
|
||||
union kbase_pm_policy_data pm_policy_data;
|
||||
bool ca_in_transition;
|
||||
bool reset_done;
|
||||
wait_queue_head_t reset_done_wait;
|
||||
wait_queue_head_t l2_powered_wait;
|
||||
int l2_powered;
|
||||
int gpu_cycle_counter_requests;
|
||||
spinlock_t gpu_cycle_counter_requests_lock;
|
||||
|
||||
u64 desired_shader_state;
|
||||
u64 powering_on_shader_state;
|
||||
u64 desired_tiler_state;
|
||||
u64 powering_on_tiler_state;
|
||||
u64 powering_on_l2_state;
|
||||
|
||||
bool gpu_in_desired_state;
|
||||
wait_queue_head_t gpu_in_desired_state_wait;
|
||||
|
||||
bool gpu_powered;
|
||||
|
||||
bool instr_enabled;
|
||||
|
||||
bool cg1_disabled;
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
bool driver_ready_for_irqs;
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
spinlock_t gpu_powered_lock;
|
||||
|
||||
|
||||
struct kbasep_pm_metrics_data metrics;
|
||||
|
||||
int gpu_poweroff_pending;
|
||||
int shader_poweroff_pending_time;
|
||||
|
||||
struct hrtimer gpu_poweroff_timer;
|
||||
struct workqueue_struct *gpu_poweroff_wq;
|
||||
struct work_struct gpu_poweroff_work;
|
||||
|
||||
u64 shader_poweroff_pending;
|
||||
|
||||
bool poweroff_timer_needed;
|
||||
|
||||
int (*callback_power_on)(struct kbase_device *kbdev);
|
||||
void (*callback_power_off)(struct kbase_device *kbdev);
|
||||
void (*callback_power_suspend)(struct kbase_device *kbdev);
|
||||
void (*callback_power_resume)(struct kbase_device *kbdev);
|
||||
int (*callback_power_runtime_on)(struct kbase_device *kbdev);
|
||||
void (*callback_power_runtime_off)(struct kbase_device *kbdev);
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
int (*callback_power_dvfs_on)(struct kbase_device *kbdev);
|
||||
int (*callback_power_change_dvfs_level)(struct kbase_device *kbdev);
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* List of policy IDs */
|
||||
enum kbase_pm_policy_id {
|
||||
KBASE_PM_POLICY_ID_DEMAND = 1,
|
||||
KBASE_PM_POLICY_ID_ALWAYS_ON,
|
||||
KBASE_PM_POLICY_ID_COARSE_DEMAND,
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
KBASE_PM_POLICY_ID_DEMAND_ALWAYS_POWERED,
|
||||
KBASE_PM_POLICY_ID_FAST_START
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef u32 kbase_pm_policy_flags;
|
||||
|
||||
/**
|
||||
* struct kbase_pm_policy - Power policy structure.
|
||||
*
|
||||
* Each power policy exposes a (static) instance of this structure which
|
||||
* contains function pointers to the policy's methods.
|
||||
*
|
||||
* @name: The name of this policy
|
||||
* @init: Function called when the policy is selected
|
||||
* @term: Function called when the policy is unselected
|
||||
* @get_core_mask: Function called to get the current shader core mask
|
||||
* @get_core_active: Function called to get the current overall GPU power
|
||||
* state
|
||||
* @flags: Field indicating flags for this policy
|
||||
* @id: Field indicating an ID for this policy. This is not
|
||||
* necessarily the same as its index in the list returned
|
||||
* by kbase_pm_list_policies().
|
||||
* It is used purely for debugging.
|
||||
*/
|
||||
struct kbase_pm_policy {
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Function called when the policy is selected
|
||||
*
|
||||
* This should initialize the kbdev->pm.pm_policy_data structure. It
|
||||
* should not attempt to make any changes to hardware state.
|
||||
*
|
||||
* It is undefined what state the cores are in when the function is
|
||||
* called.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*/
|
||||
void (*init)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called when the policy is unselected.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*/
|
||||
void (*term)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called to get the current shader core mask
|
||||
*
|
||||
* The returned mask should meet or exceed (kbdev->shader_needed_bitmap
|
||||
* | kbdev->shader_inuse_bitmap).
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*
|
||||
* Return: The mask of shader cores to be powered
|
||||
*/
|
||||
u64 (*get_core_mask)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called to get the current overall GPU power state
|
||||
*
|
||||
* This function should consider the state of kbdev->pm.active_count. If
|
||||
* this count is greater than 0 then there is at least one active
|
||||
* context on the device and the GPU should be powered. If it is equal
|
||||
* to 0 then there are no active contexts and the GPU could be powered
|
||||
* off if desired.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*
|
||||
* Return: true if the GPU should be powered, false otherwise
|
||||
*/
|
||||
bool (*get_core_active)(struct kbase_device *kbdev);
|
||||
|
||||
kbase_pm_policy_flags flags;
|
||||
enum kbase_pm_policy_id id;
|
||||
};
|
||||
|
||||
|
||||
enum kbase_pm_ca_policy_id {
|
||||
KBASE_PM_CA_POLICY_ID_FIXED = 1,
|
||||
KBASE_PM_CA_POLICY_ID_RANDOM
|
||||
};
|
||||
|
||||
typedef u32 kbase_pm_ca_policy_flags;
|
||||
|
||||
/**
|
||||
* struct kbase_pm_ca_policy - Core availability policy structure.
|
||||
*
|
||||
* Each core availability policy exposes a (static) instance of this structure
|
||||
* which contains function pointers to the policy's methods.
|
||||
*
|
||||
* @name: The name of this policy
|
||||
* @init: Function called when the policy is selected
|
||||
* @term: Function called when the policy is unselected
|
||||
* @get_core_mask: Function called to get the current shader core
|
||||
* availability mask
|
||||
* @update_core_status: Function called to update the current core status
|
||||
* @flags: Field indicating flags for this policy
|
||||
* @id: Field indicating an ID for this policy. This is not
|
||||
* necessarily the same as its index in the list returned
|
||||
* by kbase_pm_list_policies().
|
||||
* It is used purely for debugging.
|
||||
*/
|
||||
struct kbase_pm_ca_policy {
|
||||
char *name;
|
||||
|
||||
/**
|
||||
* Function called when the policy is selected
|
||||
*
|
||||
* This should initialize the kbdev->pm.ca_policy_data structure. It
|
||||
* should not attempt to make any changes to hardware state.
|
||||
*
|
||||
* It is undefined what state the cores are in when the function is
|
||||
* called.
|
||||
*
|
||||
* @kbdev The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*/
|
||||
void (*init)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called when the policy is unselected.
|
||||
*
|
||||
* @kbdev The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*/
|
||||
void (*term)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called to get the current shader core availability mask
|
||||
*
|
||||
* When a change in core availability is occurring, the policy must set
|
||||
* kbdev->pm.ca_in_transition to true. This is to indicate that
|
||||
* reporting changes in power state cannot be optimized out, even if
|
||||
* kbdev->pm.desired_shader_state remains unchanged. This must be done
|
||||
* by any functions internal to the Core Availability Policy that change
|
||||
* the return value of kbase_pm_ca_policy::get_core_mask.
|
||||
*
|
||||
* @kbdev The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
*
|
||||
* Return: The current core availability mask
|
||||
*/
|
||||
u64 (*get_core_mask)(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Function called to update the current core status
|
||||
*
|
||||
* If none of the cores in core group 0 are ready or transitioning, then
|
||||
* the policy must ensure that the next call to get_core_mask does not
|
||||
* return 0 for all cores in core group 0. It is an error to disable
|
||||
* core group 0 through the core availability policy.
|
||||
*
|
||||
* When a change in core availability has finished, the policy must set
|
||||
* kbdev->pm.ca_in_transition to false. This is to indicate that
|
||||
* changes in power state can once again be optimized out when
|
||||
* kbdev->pm.desired_shader_state is unchanged.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* (must be a valid pointer)
|
||||
* @cores_ready: The mask of cores currently powered and
|
||||
* ready to run jobs
|
||||
* @cores_transitioning: The mask of cores currently transitioning
|
||||
* power state
|
||||
*/
|
||||
void (*update_core_status)(struct kbase_device *kbdev, u64 cores_ready,
|
||||
u64 cores_transitioning);
|
||||
|
||||
kbase_pm_ca_policy_flags flags;
|
||||
|
||||
/**
|
||||
* Field indicating an ID for this policy. This is not necessarily the
|
||||
* same as its index in the list returned by kbase_pm_list_policies().
|
||||
* It is used purely for debugging.
|
||||
*/
|
||||
enum kbase_pm_ca_policy_id id;
|
||||
};
|
||||
|
||||
#endif /* _KBASE_PM_HWACCESS_DEFS_H_ */
|
||||
72
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_demand.c
Normal file
72
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_demand.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A simple demand based power management policy
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
|
||||
static u64 demand_get_core_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
u64 desired = kbdev->shader_needed_bitmap | kbdev->shader_inuse_bitmap;
|
||||
|
||||
if (0 == kbdev->pm.active_count)
|
||||
return 0;
|
||||
|
||||
return desired;
|
||||
}
|
||||
|
||||
static bool demand_get_core_active(struct kbase_device *kbdev)
|
||||
{
|
||||
if (0 == kbdev->pm.active_count && !(kbdev->shader_needed_bitmap |
|
||||
kbdev->shader_inuse_bitmap))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void demand_init(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
static void demand_term(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* The struct kbase_pm_policy structure for the demand power policy.
|
||||
*
|
||||
* This is the static structure that defines the demand power policy's callback
|
||||
* and name.
|
||||
*/
|
||||
const struct kbase_pm_policy kbase_pm_demand_policy_ops = {
|
||||
"demand", /* name */
|
||||
demand_init, /* init */
|
||||
demand_term, /* term */
|
||||
demand_get_core_mask, /* get_core_mask */
|
||||
demand_get_core_active, /* get_core_active */
|
||||
0u, /* flags */
|
||||
KBASE_PM_POLICY_ID_DEMAND, /* id */
|
||||
};
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_demand_policy_ops);
|
||||
64
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_demand.h
Normal file
64
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_demand.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* A simple demand based power management policy
|
||||
*/
|
||||
|
||||
#ifndef MALI_KBASE_PM_DEMAND_H
|
||||
#define MALI_KBASE_PM_DEMAND_H
|
||||
|
||||
/**
|
||||
* DOC: Demand power management policy
|
||||
*
|
||||
* The demand power management policy has the following characteristics:
|
||||
* - When KBase indicates that the GPU will be powered up, but we don't yet
|
||||
* know which Job Chains are to be run:
|
||||
* - The Shader Cores are not powered up
|
||||
*
|
||||
* - When KBase indicates that a set of Shader Cores are needed to submit the
|
||||
* currently queued Job Chains:
|
||||
* - Only those Shader Cores are powered up
|
||||
*
|
||||
* - When KBase indicates that the GPU need not be powered:
|
||||
* - The Shader Cores are powered off, and the GPU itself is powered off too.
|
||||
*
|
||||
* Note:
|
||||
* - KBase indicates the GPU will be powered up when it has a User Process that
|
||||
* has just started to submit Job Chains.
|
||||
*
|
||||
* - KBase indicates the GPU need not be powered when all the Job Chains from
|
||||
* User Processes have finished, and it is waiting for a User Process to
|
||||
* submit some more Job Chains.
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct kbasep_pm_policy_demand - Private structure for policy instance data
|
||||
*
|
||||
* @dummy: No state is needed, a dummy variable
|
||||
*
|
||||
* This contains data that is private to the demand power policy.
|
||||
*/
|
||||
struct kbasep_pm_policy_demand {
|
||||
int dummy;
|
||||
};
|
||||
|
||||
extern const struct kbase_pm_policy kbase_pm_demand_policy_ops;
|
||||
|
||||
#endif /* MALI_KBASE_PM_DEMAND_H */
|
||||
1476
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_driver.c
Normal file
1476
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_driver.c
Normal file
File diff suppressed because it is too large
Load diff
516
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_internal.h
Normal file
516
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_internal.h
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Power management API definitions used internally by GPU backend
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_BACKEND_PM_INTERNAL_H_
|
||||
#define _KBASE_BACKEND_PM_INTERNAL_H_
|
||||
|
||||
#include <mali_kbase_hwaccess_pm.h>
|
||||
|
||||
#include "mali_kbase_pm_ca.h"
|
||||
#include "mali_kbase_pm_policy.h"
|
||||
|
||||
|
||||
/**
|
||||
* kbase_pm_dev_idle - The GPU is idle.
|
||||
*
|
||||
* The OS may choose to turn off idle devices
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_dev_idle(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_dev_activate - The GPU is active.
|
||||
*
|
||||
* The OS should avoid opportunistically turning off the GPU while it is active
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_dev_activate(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_get_present_cores - Get details of the cores that are present in
|
||||
* the device.
|
||||
*
|
||||
* This function can be called by the active power policy to return a bitmask of
|
||||
* the cores (of a specified type) present in the GPU device and also a count of
|
||||
* the number of cores.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @type: The type of core (see the enum kbase_pm_core_type enumeration)
|
||||
*
|
||||
* Return: The bit mask of cores present
|
||||
*/
|
||||
u64 kbase_pm_get_present_cores(struct kbase_device *kbdev,
|
||||
enum kbase_pm_core_type type);
|
||||
|
||||
/**
|
||||
* kbase_pm_get_active_cores - Get details of the cores that are currently
|
||||
* active in the device.
|
||||
*
|
||||
* This function can be called by the active power policy to return a bitmask of
|
||||
* the cores (of a specified type) that are actively processing work (i.e.
|
||||
* turned on *and* busy).
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @type: The type of core (see the enum kbase_pm_core_type enumeration)
|
||||
*
|
||||
* Return: The bit mask of active cores
|
||||
*/
|
||||
u64 kbase_pm_get_active_cores(struct kbase_device *kbdev,
|
||||
enum kbase_pm_core_type type);
|
||||
|
||||
/**
|
||||
* kbase_pm_get_trans_cores - Get details of the cores that are currently
|
||||
* transitioning between power states.
|
||||
*
|
||||
* This function can be called by the active power policy to return a bitmask of
|
||||
* the cores (of a specified type) that are currently transitioning between
|
||||
* power states.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @type: The type of core (see the enum kbase_pm_core_type enumeration)
|
||||
*
|
||||
* Return: The bit mask of transitioning cores
|
||||
*/
|
||||
u64 kbase_pm_get_trans_cores(struct kbase_device *kbdev,
|
||||
enum kbase_pm_core_type type);
|
||||
|
||||
/**
|
||||
* kbase_pm_get_ready_cores - Get details of the cores that are currently
|
||||
* powered and ready for jobs.
|
||||
*
|
||||
* This function can be called by the active power policy to return a bitmask of
|
||||
* the cores (of a specified type) that are powered and ready for jobs (they may
|
||||
* or may not be currently executing jobs).
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @type: The type of core (see the enum kbase_pm_core_type enumeration)
|
||||
*
|
||||
* Return: The bit mask of ready cores
|
||||
*/
|
||||
u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev,
|
||||
enum kbase_pm_core_type type);
|
||||
|
||||
/**
|
||||
* kbase_pm_clock_on - Turn the clock for the device on, and enable device
|
||||
* interrupts.
|
||||
*
|
||||
* This function can be used by a power policy to turn the clock for the GPU on.
|
||||
* It should be modified during integration to perform the necessary actions to
|
||||
* ensure that the GPU is fully powered and clocked.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @is_resume: true if clock on due to resume after suspend, false otherwise
|
||||
*/
|
||||
void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume);
|
||||
|
||||
/**
|
||||
* kbase_pm_clock_off - Disable device interrupts, and turn the clock for the
|
||||
* device off.
|
||||
*
|
||||
* This function can be used by a power policy to turn the clock for the GPU
|
||||
* off. It should be modified during integration to perform the necessary
|
||||
* actions to turn the clock off (if this is possible in the integration).
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @is_suspend: true if clock off due to suspend, false otherwise
|
||||
*
|
||||
* Return: true if clock was turned off, or
|
||||
* false if clock can not be turned off due to pending page/bus fault
|
||||
* workers. Caller must flush MMU workqueues and retry
|
||||
*/
|
||||
bool kbase_pm_clock_off(struct kbase_device *kbdev, bool is_suspend);
|
||||
|
||||
/**
|
||||
* kbase_pm_enable_interrupts - Enable interrupts on the device.
|
||||
*
|
||||
* Interrupts are also enabled after a call to kbase_pm_clock_on().
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_enable_interrupts(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_enable_interrupts_mmu_mask - Enable interrupts on the device, using
|
||||
* the provided mask to set MMU_IRQ_MASK.
|
||||
*
|
||||
* Interrupts are also enabled after a call to kbase_pm_clock_on().
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @mask: The mask to use for MMU_IRQ_MASK
|
||||
*/
|
||||
void kbase_pm_enable_interrupts_mmu_mask(struct kbase_device *kbdev, u32 mask);
|
||||
|
||||
/**
|
||||
* kbase_pm_disable_interrupts - Disable interrupts on the device.
|
||||
*
|
||||
* This prevents delivery of Power Management interrupts to the CPU so that
|
||||
* kbase_pm_check_transitions_nolock() will not be called from the IRQ handler
|
||||
* until kbase_pm_enable_interrupts() or kbase_pm_clock_on() is called.
|
||||
*
|
||||
* Interrupts are also disabled after a call to kbase_pm_clock_off().
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_disable_interrupts(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_init_hw - Initialize the hardware.
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @flags: Flags specifying the type of PM init
|
||||
*
|
||||
* This function checks the GPU ID register to ensure that the GPU is supported
|
||||
* by the driver and performs a reset on the device so that it is in a known
|
||||
* state before the device is used.
|
||||
*
|
||||
* Return: 0 if the device is supported and successfully reset.
|
||||
*/
|
||||
int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags);
|
||||
|
||||
/**
|
||||
* kbase_pm_reset_done - The GPU has been reset successfully.
|
||||
*
|
||||
* This function must be called by the GPU interrupt handler when the
|
||||
* RESET_COMPLETED bit is set. It signals to the power management initialization
|
||||
* code that the GPU has been successfully reset.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_reset_done(struct kbase_device *kbdev);
|
||||
|
||||
|
||||
/**
|
||||
* kbase_pm_check_transitions_nolock - Check if there are any power transitions
|
||||
* to make, and if so start them.
|
||||
*
|
||||
* This function will check the desired_xx_state members of
|
||||
* struct kbase_pm_device_data and the actual status of the hardware to see if
|
||||
* any power transitions can be made at this time to make the hardware state
|
||||
* closer to the state desired by the power policy.
|
||||
*
|
||||
* The return value can be used to check whether all the desired cores are
|
||||
* available, and so whether it's worth submitting a job (e.g. from a Power
|
||||
* Management IRQ).
|
||||
*
|
||||
* Note that this still returns true when desired_xx_state has no
|
||||
* cores. That is: of the no cores desired, none were *un*available. In
|
||||
* this case, the caller may still need to try submitting jobs. This is because
|
||||
* the Core Availability Policy might have taken us to an intermediate state
|
||||
* where no cores are powered, before powering on more cores (e.g. for core
|
||||
* rotation)
|
||||
*
|
||||
* The caller must hold kbase_device.pm.power_change_lock
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Return: non-zero when all desired cores are available. That is,
|
||||
* it's worthwhile for the caller to submit a job.
|
||||
* false otherwise
|
||||
*/
|
||||
bool kbase_pm_check_transitions_nolock(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_check_transitions_sync - Synchronous and locking variant of
|
||||
* kbase_pm_check_transitions_nolock()
|
||||
*
|
||||
* On returning, the desired state at the time of the call will have been met.
|
||||
*
|
||||
* There is nothing to stop the core being switched off by calls to
|
||||
* kbase_pm_release_cores() or kbase_pm_unrequest_cores(). Therefore, the
|
||||
* caller must have already made a call to
|
||||
* kbase_pm_request_cores()/kbase_pm_request_cores_sync() previously.
|
||||
*
|
||||
* The usual use-case for this is to ensure cores are 'READY' after performing
|
||||
* a GPU Reset.
|
||||
*
|
||||
* Unlike kbase_pm_check_transitions_nolock(), the caller must not hold
|
||||
* kbase_device.pm.power_change_lock, because this function will take that
|
||||
* lock itself.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_check_transitions_sync(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_update_cores_state_nolock - Variant of kbase_pm_update_cores_state()
|
||||
* where the caller must hold
|
||||
* kbase_device.pm.power_change_lock
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_update_cores_state_nolock(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_update_cores_state - Update the desired state of shader cores from
|
||||
* the Power Policy, and begin any power
|
||||
* transitions.
|
||||
*
|
||||
* This function will update the desired_xx_state members of
|
||||
* struct kbase_pm_device_data by calling into the current Power Policy. It will
|
||||
* then begin power transitions to make the hardware acheive the desired shader
|
||||
* core state.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_update_cores_state(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_cancel_deferred_poweroff - Cancel any pending requests to power off
|
||||
* the GPU and/or shader cores.
|
||||
*
|
||||
* This should be called by any functions which directly power off the GPU.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_cancel_deferred_poweroff(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbasep_pm_read_present_cores - Read the bitmasks of present cores.
|
||||
*
|
||||
* This information is cached to avoid having to perform register reads whenever
|
||||
* the information is required.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbasep_pm_read_present_cores(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbasep_pm_metrics_init - Initialize the metrics gathering framework.
|
||||
*
|
||||
* This must be called before other metric gathering APIs are called.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Return: 0 on success, error code on error
|
||||
*/
|
||||
int kbasep_pm_metrics_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbasep_pm_metrics_term - Terminate the metrics gathering framework.
|
||||
*
|
||||
* This must be called when metric gathering is no longer required. It is an
|
||||
* error to call any metrics gathering function (other than
|
||||
* kbasep_pm_metrics_init()) after calling this function.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbasep_pm_metrics_term(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_report_vsync - Function to be called by the frame buffer driver to
|
||||
* update the vsync metric.
|
||||
*
|
||||
* This function should be called by the frame buffer driver to update whether
|
||||
* the system is hitting the vsync target or not. buffer_updated should be true
|
||||
* if the vsync corresponded with a new frame being displayed, otherwise it
|
||||
* should be false. This function does not need to be called every vsync, but
|
||||
* only when the value of @buffer_updated differs from a previous call.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
* @buffer_updated: True if the buffer has been updated on this VSync,
|
||||
* false otherwise
|
||||
*/
|
||||
void kbase_pm_report_vsync(struct kbase_device *kbdev, int buffer_updated);
|
||||
|
||||
/**
|
||||
* kbase_pm_get_dvfs_action - Determine whether the DVFS system should change
|
||||
* the clock speed of the GPU.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* This function should be called regularly by the DVFS system to check whether
|
||||
* the clock speed of the GPU needs updating.
|
||||
*/
|
||||
void kbase_pm_get_dvfs_action(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_gpu_cycle_counter - Mark that the GPU cycle counter is
|
||||
* needed
|
||||
*
|
||||
* If the caller is the first caller then the GPU cycle counters will be enabled
|
||||
* along with the l2 cache
|
||||
*
|
||||
* The GPU must be powered when calling this function (i.e.
|
||||
* kbase_pm_context_active() must have been called).
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_request_gpu_cycle_counter(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_gpu_cycle_counter_l2_is_on - Mark GPU cycle counter is
|
||||
* needed (l2 cache already on)
|
||||
*
|
||||
* This is a version of the above function
|
||||
* (kbase_pm_request_gpu_cycle_counter()) suitable for being called when the
|
||||
* l2 cache is known to be on and assured to be on until the subsequent call of
|
||||
* kbase_pm_release_gpu_cycle_counter() such as when a job is submitted. It does
|
||||
* not sleep and can be called from atomic functions.
|
||||
*
|
||||
* The GPU must be powered when calling this function (i.e.
|
||||
* kbase_pm_context_active() must have been called) and the l2 cache must be
|
||||
* powered on.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_request_gpu_cycle_counter_l2_is_on(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_release_gpu_cycle_counter - Mark that the GPU cycle counter is no
|
||||
* longer in use
|
||||
*
|
||||
* If the caller is the
|
||||
* last caller then the GPU cycle counters will be disabled. A request must have
|
||||
* been made before a call to this.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_release_gpu_cycle_counter(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_register_access_enable - Enable access to GPU registers
|
||||
*
|
||||
* Enables access to the GPU registers before power management has powered up
|
||||
* the GPU with kbase_pm_powerup().
|
||||
*
|
||||
* Access to registers should be done using kbase_os_reg_read()/write() at this
|
||||
* stage, not kbase_reg_read()/write().
|
||||
*
|
||||
* This results in the power management callbacks provided in the driver
|
||||
* configuration to get called to turn on power and/or clocks to the GPU. See
|
||||
* kbase_pm_callback_conf.
|
||||
*
|
||||
* This should only be used before power management is powered up with
|
||||
* kbase_pm_powerup()
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_register_access_enable(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_register_access_disable - Disable early register access
|
||||
*
|
||||
* Disables access to the GPU registers enabled earlier by a call to
|
||||
* kbase_pm_register_access_enable().
|
||||
*
|
||||
* This results in the power management callbacks provided in the driver
|
||||
* configuration to get called to turn off power and/or clocks to the GPU. See
|
||||
* kbase_pm_callback_conf
|
||||
*
|
||||
* This should only be used before power management is powered up with
|
||||
* kbase_pm_powerup()
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_register_access_disable(struct kbase_device *kbdev);
|
||||
|
||||
/* NOTE: kbase_pm_is_suspending is in mali_kbase.h, because it is an inline
|
||||
* function */
|
||||
|
||||
/**
|
||||
* kbase_pm_metrics_is_active - Check if the power management metrics
|
||||
* collection is active.
|
||||
*
|
||||
* Note that this returns if the power management metrics collection was
|
||||
* active at the time of calling, it is possible that after the call the metrics
|
||||
* collection enable may have changed state.
|
||||
*
|
||||
* The caller must handle the consequence that the state may have changed.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* Return: true if metrics collection was active else false.
|
||||
*/
|
||||
bool kbase_pm_metrics_is_active(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_do_poweron - Power on the GPU, and any cores that are requested.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @is_resume: true if power on due to resume after suspend,
|
||||
* false otherwise
|
||||
*/
|
||||
void kbase_pm_do_poweron(struct kbase_device *kbdev, bool is_resume);
|
||||
|
||||
/**
|
||||
* kbase_pm_do_poweroff - Power off the GPU, and any cores that have been
|
||||
* requested.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @is_suspend: true if power off due to suspend,
|
||||
* false otherwise
|
||||
* Return:
|
||||
* true if power was turned off, else
|
||||
* false if power can not be turned off due to pending page/bus
|
||||
* fault workers. Caller must flush MMU workqueues and retry
|
||||
*/
|
||||
bool kbase_pm_do_poweroff(struct kbase_device *kbdev, bool is_suspend);
|
||||
|
||||
#ifdef CONFIG_PM_DEVFREQ
|
||||
void kbase_pm_get_dvfs_utilisation(struct kbase_device *kbdev,
|
||||
unsigned long *total, unsigned long *busy);
|
||||
void kbase_pm_reset_dvfs_utilisation(struct kbase_device *kbdev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
|
||||
/**
|
||||
* kbase_platform_dvfs_event - Report utilisation to DVFS code
|
||||
*
|
||||
* Function provided by platform specific code when DVFS is enabled to allow
|
||||
* the power management metrics system to report utilisation.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
* @utilisation: The current calculated utilisation by the metrics system.
|
||||
* @util_gl_share: The current calculated gl share of utilisation.
|
||||
* @util_cl_share: The current calculated cl share of utilisation per core
|
||||
* group.
|
||||
* Return: Returns 0 on failure and non zero on success.
|
||||
*/
|
||||
|
||||
int kbase_platform_dvfs_event(struct kbase_device *kbdev, u32 utilisation,
|
||||
u32 util_gl_share, u32 util_cl_share[2]);
|
||||
#endif
|
||||
|
||||
void kbase_pm_power_changed(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_metrics_update - Inform the metrics system that an atom is either
|
||||
* about to be run or has just completed.
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @now: Pointer to the timestamp of the change, or NULL to use current time
|
||||
*
|
||||
* Caller must hold runpool_irq.lock
|
||||
*/
|
||||
void kbase_pm_metrics_update(struct kbase_device *kbdev,
|
||||
ktime_t *now);
|
||||
|
||||
|
||||
#endif /* _KBASE_BACKEND_PM_INTERNAL_H_ */
|
||||
422
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_metrics.c
Normal file
422
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_metrics.c
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Metrics for power management
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
#include <backend/gpu/mali_kbase_jm_rb.h>
|
||||
|
||||
/* When VSync is being hit aim for utilisation between 70-90% */
|
||||
#define KBASE_PM_VSYNC_MIN_UTILISATION 70
|
||||
#define KBASE_PM_VSYNC_MAX_UTILISATION 90
|
||||
/* Otherwise aim for 10-40% */
|
||||
#define KBASE_PM_NO_VSYNC_MIN_UTILISATION 10
|
||||
#define KBASE_PM_NO_VSYNC_MAX_UTILISATION 40
|
||||
|
||||
/* Shift used for kbasep_pm_metrics_data.time_busy/idle - units of (1 << 8) ns
|
||||
* This gives a maximum period between samples of 2^(32+8)/100 ns = slightly
|
||||
* under 11s. Exceeding this will cause overflow */
|
||||
#define KBASE_PM_TIME_SHIFT 8
|
||||
|
||||
/* Maximum time between sampling of utilization data, without resetting the
|
||||
* counters. */
|
||||
#define MALI_UTILIZATION_MAX_PERIOD 100000 /* ns = 100ms */
|
||||
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
static enum hrtimer_restart dvfs_callback(struct hrtimer *timer)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbasep_pm_metrics_data *metrics;
|
||||
|
||||
KBASE_DEBUG_ASSERT(timer != NULL);
|
||||
|
||||
metrics = container_of(timer, struct kbasep_pm_metrics_data, timer);
|
||||
kbase_pm_get_dvfs_action(metrics->kbdev);
|
||||
|
||||
spin_lock_irqsave(&metrics->lock, flags);
|
||||
|
||||
if (metrics->timer_active)
|
||||
hrtimer_start(timer,
|
||||
HR_TIMER_DELAY_MSEC(metrics->kbdev->pm.dvfs_period),
|
||||
HRTIMER_MODE_REL);
|
||||
|
||||
spin_unlock_irqrestore(&metrics->lock, flags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
#endif /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
|
||||
int kbasep_pm_metrics_init(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
kbdev->pm.backend.metrics.kbdev = kbdev;
|
||||
|
||||
kbdev->pm.backend.metrics.time_period_start = ktime_get();
|
||||
kbdev->pm.backend.metrics.time_busy = 0;
|
||||
kbdev->pm.backend.metrics.time_idle = 0;
|
||||
kbdev->pm.backend.metrics.prev_busy = 0;
|
||||
kbdev->pm.backend.metrics.prev_idle = 0;
|
||||
kbdev->pm.backend.metrics.gpu_active = false;
|
||||
kbdev->pm.backend.metrics.active_cl_ctx[0] = 0;
|
||||
kbdev->pm.backend.metrics.active_cl_ctx[1] = 0;
|
||||
kbdev->pm.backend.metrics.active_gl_ctx[0] = 0;
|
||||
kbdev->pm.backend.metrics.active_gl_ctx[1] = 0;
|
||||
kbdev->pm.backend.metrics.busy_cl[0] = 0;
|
||||
kbdev->pm.backend.metrics.busy_cl[1] = 0;
|
||||
kbdev->pm.backend.metrics.busy_gl = 0;
|
||||
|
||||
spin_lock_init(&kbdev->pm.backend.metrics.lock);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if(kbdev->vendor_callbacks->pm_metrics_init)
|
||||
kbdev->vendor_callbacks->pm_metrics_init(kbdev);
|
||||
else
|
||||
{
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
kbdev->pm.backend.metrics.timer_active = true;
|
||||
hrtimer_init(&kbdev->pm.backend.metrics.timer, CLOCK_MONOTONIC,
|
||||
HRTIMER_MODE_REL);
|
||||
kbdev->pm.backend.metrics.timer.function = dvfs_callback;
|
||||
|
||||
hrtimer_start(&kbdev->pm.backend.metrics.timer,
|
||||
HR_TIMER_DELAY_MSEC(kbdev->pm.dvfs_period),
|
||||
HRTIMER_MODE_REL);
|
||||
#endif /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
}
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if(kbdev->vendor_callbacks->cl_boost_init)
|
||||
kbdev->vendor_callbacks->cl_boost_init(kbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbasep_pm_metrics_init);
|
||||
|
||||
void kbasep_pm_metrics_term(struct kbase_device *kbdev)
|
||||
{
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
kbdev->pm.backend.metrics.timer_active = false;
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
|
||||
hrtimer_cancel(&kbdev->pm.backend.metrics.timer);
|
||||
#endif /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if(kbdev->vendor_callbacks->pm_metrics_term)
|
||||
kbdev->vendor_callbacks->pm_metrics_term(kbdev);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbasep_pm_metrics_term);
|
||||
|
||||
/* caller needs to hold kbdev->pm.backend.metrics.lock before calling this
|
||||
* function
|
||||
*/
|
||||
static void kbase_pm_get_dvfs_utilisation_calc(struct kbase_device *kbdev,
|
||||
ktime_t now)
|
||||
{
|
||||
ktime_t diff;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.backend.metrics.lock);
|
||||
|
||||
diff = ktime_sub(now, kbdev->pm.backend.metrics.time_period_start);
|
||||
if (ktime_to_ns(diff) < 0)
|
||||
return;
|
||||
|
||||
if (kbdev->pm.backend.metrics.gpu_active) {
|
||||
u32 ns_time = (u32) (ktime_to_ns(diff) >> KBASE_PM_TIME_SHIFT);
|
||||
|
||||
kbdev->pm.backend.metrics.time_busy += ns_time;
|
||||
if (kbdev->pm.backend.metrics.active_cl_ctx[0])
|
||||
kbdev->pm.backend.metrics.busy_cl[0] += ns_time;
|
||||
if (kbdev->pm.backend.metrics.active_cl_ctx[1])
|
||||
kbdev->pm.backend.metrics.busy_cl[1] += ns_time;
|
||||
if (kbdev->pm.backend.metrics.active_gl_ctx[0])
|
||||
kbdev->pm.backend.metrics.busy_gl += ns_time;
|
||||
if (kbdev->pm.backend.metrics.active_gl_ctx[1])
|
||||
kbdev->pm.backend.metrics.busy_gl += ns_time;
|
||||
} else {
|
||||
kbdev->pm.backend.metrics.time_idle += (u32) (ktime_to_ns(diff)
|
||||
>> KBASE_PM_TIME_SHIFT);
|
||||
}
|
||||
|
||||
kbdev->pm.backend.metrics.time_period_start = now;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_DEVFREQ) || defined(CONFIG_MALI_MIDGARD_DVFS)
|
||||
/* Caller needs to hold kbdev->pm.backend.metrics.lock before calling this
|
||||
* function.
|
||||
*/
|
||||
static void kbase_pm_reset_dvfs_utilisation_unlocked(struct kbase_device *kbdev,
|
||||
ktime_t now)
|
||||
{
|
||||
/* Store previous value */
|
||||
kbdev->pm.backend.metrics.prev_idle =
|
||||
kbdev->pm.backend.metrics.time_idle;
|
||||
kbdev->pm.backend.metrics.prev_busy =
|
||||
kbdev->pm.backend.metrics.time_busy;
|
||||
|
||||
/* Reset current values */
|
||||
kbdev->pm.backend.metrics.time_period_start = now;
|
||||
kbdev->pm.backend.metrics.time_idle = 0;
|
||||
kbdev->pm.backend.metrics.time_busy = 0;
|
||||
kbdev->pm.backend.metrics.busy_cl[0] = 0;
|
||||
kbdev->pm.backend.metrics.busy_cl[1] = 0;
|
||||
kbdev->pm.backend.metrics.busy_gl = 0;
|
||||
}
|
||||
|
||||
void kbase_pm_reset_dvfs_utilisation(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, ktime_get());
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
}
|
||||
|
||||
void kbase_pm_get_dvfs_utilisation(struct kbase_device *kbdev,
|
||||
unsigned long *total_out, unsigned long *busy_out)
|
||||
{
|
||||
ktime_t now = ktime_get();
|
||||
unsigned long flags, busy, total;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
kbase_pm_get_dvfs_utilisation_calc(kbdev, now);
|
||||
|
||||
busy = kbdev->pm.backend.metrics.time_busy;
|
||||
total = busy + kbdev->pm.backend.metrics.time_idle;
|
||||
|
||||
/* Reset stats if older than MALI_UTILIZATION_MAX_PERIOD (default
|
||||
* 100ms) */
|
||||
if (total >= MALI_UTILIZATION_MAX_PERIOD) {
|
||||
kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, now);
|
||||
} else if (total < (MALI_UTILIZATION_MAX_PERIOD / 2)) {
|
||||
total += kbdev->pm.backend.metrics.prev_idle +
|
||||
kbdev->pm.backend.metrics.prev_busy;
|
||||
busy += kbdev->pm.backend.metrics.prev_busy;
|
||||
}
|
||||
|
||||
*total_out = total;
|
||||
*busy_out = busy;
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
|
||||
/* caller needs to hold kbdev->pm.backend.metrics.lock before calling this
|
||||
* function
|
||||
*/
|
||||
int kbase_pm_get_dvfs_utilisation_old(struct kbase_device *kbdev,
|
||||
int *util_gl_share,
|
||||
int util_cl_share[2],
|
||||
ktime_t now)
|
||||
{
|
||||
int utilisation;
|
||||
int busy;
|
||||
|
||||
kbase_pm_get_dvfs_utilisation_calc(kbdev, now);
|
||||
|
||||
if (kbdev->pm.backend.metrics.time_idle +
|
||||
kbdev->pm.backend.metrics.time_busy == 0) {
|
||||
/* No data - so we return NOP */
|
||||
utilisation = -1;
|
||||
if (util_gl_share)
|
||||
*util_gl_share = -1;
|
||||
if (util_cl_share) {
|
||||
util_cl_share[0] = -1;
|
||||
util_cl_share[1] = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
utilisation = (100 * kbdev->pm.backend.metrics.time_busy) /
|
||||
(kbdev->pm.backend.metrics.time_idle +
|
||||
kbdev->pm.backend.metrics.time_busy);
|
||||
|
||||
busy = kbdev->pm.backend.metrics.busy_gl +
|
||||
kbdev->pm.backend.metrics.busy_cl[0] +
|
||||
kbdev->pm.backend.metrics.busy_cl[1];
|
||||
|
||||
if (busy != 0) {
|
||||
if (util_gl_share)
|
||||
*util_gl_share =
|
||||
(100 * kbdev->pm.backend.metrics.busy_gl) /
|
||||
busy;
|
||||
if (util_cl_share) {
|
||||
util_cl_share[0] =
|
||||
(100 * kbdev->pm.backend.metrics.busy_cl[0]) /
|
||||
busy;
|
||||
util_cl_share[1] =
|
||||
(100 * kbdev->pm.backend.metrics.busy_cl[1]) /
|
||||
busy;
|
||||
}
|
||||
} else {
|
||||
if (util_gl_share)
|
||||
*util_gl_share = -1;
|
||||
if (util_cl_share) {
|
||||
util_cl_share[0] = -1;
|
||||
util_cl_share[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return utilisation;
|
||||
}
|
||||
|
||||
void kbase_pm_get_dvfs_action(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
int utilisation, util_gl_share;
|
||||
int util_cl_share[2];
|
||||
ktime_t now;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
|
||||
now = ktime_get();
|
||||
|
||||
utilisation = kbase_pm_get_dvfs_utilisation_old(kbdev, &util_gl_share,
|
||||
util_cl_share, now);
|
||||
|
||||
if (utilisation < 0 || util_gl_share < 0 || util_cl_share[0] < 0 ||
|
||||
util_cl_share[1] < 0) {
|
||||
utilisation = 0;
|
||||
util_gl_share = 0;
|
||||
util_cl_share[0] = 0;
|
||||
util_cl_share[1] = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
#ifdef CONFIG_MALI_MIDGARD_DVFS
|
||||
kbase_platform_dvfs_event(kbdev, utilisation, util_gl_share,
|
||||
util_cl_share);
|
||||
#endif /*CONFIG_MALI_MIDGARD_DVFS */
|
||||
|
||||
kbase_pm_reset_dvfs_utilisation_unlocked(kbdev, now);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
}
|
||||
|
||||
bool kbase_pm_metrics_is_active(struct kbase_device *kbdev)
|
||||
{
|
||||
bool isactive;
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
isactive = kbdev->pm.backend.metrics.timer_active;
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
|
||||
return isactive;
|
||||
}
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_metrics_is_active);
|
||||
|
||||
#endif /* CONFIG_MALI_MIDGARD_DVFS */
|
||||
|
||||
/**
|
||||
* kbase_pm_metrics_active_calc - Update PM active counts based on currently
|
||||
* running atoms
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* The caller must hold kbdev->pm.backend.metrics.lock
|
||||
*/
|
||||
static void kbase_pm_metrics_active_calc(struct kbase_device *kbdev)
|
||||
{
|
||||
int js;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.backend.metrics.lock);
|
||||
|
||||
kbdev->pm.backend.metrics.active_gl_ctx[0] = 0;
|
||||
kbdev->pm.backend.metrics.active_gl_ctx[1] = 0;
|
||||
kbdev->pm.backend.metrics.active_cl_ctx[0] = 0;
|
||||
kbdev->pm.backend.metrics.active_cl_ctx[1] = 0;
|
||||
#ifdef MALI_SEC_UTILIZATION
|
||||
/*Setting gpu_active here may show real GPU utilization but it can't make full utilization(100%) */
|
||||
#else
|
||||
kbdev->pm.backend.metrics.gpu_active = false;
|
||||
#endif
|
||||
|
||||
for (js = 0; js < BASE_JM_MAX_NR_SLOTS; js++) {
|
||||
struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, 0);
|
||||
|
||||
/* Head atom may have just completed, so if it isn't running
|
||||
* then try the next atom */
|
||||
if (katom && katom->gpu_rb_state != KBASE_ATOM_GPU_RB_SUBMITTED)
|
||||
katom = kbase_gpu_inspect(kbdev, js, 1);
|
||||
|
||||
if (katom && katom->gpu_rb_state ==
|
||||
KBASE_ATOM_GPU_RB_SUBMITTED) {
|
||||
if (katom->core_req & BASE_JD_REQ_ONLY_COMPUTE) {
|
||||
int device_nr = (katom->core_req &
|
||||
BASE_JD_REQ_SPECIFIC_COHERENT_GROUP)
|
||||
? katom->device_nr : 0;
|
||||
WARN_ON(device_nr >= 2);
|
||||
kbdev->pm.backend.metrics.active_cl_ctx[
|
||||
device_nr] = 1;
|
||||
} else {
|
||||
/* Slot 2 should not be running non-compute
|
||||
* atoms */
|
||||
WARN_ON(js >= 2);
|
||||
kbdev->pm.backend.metrics.active_gl_ctx[js] = 1;
|
||||
}
|
||||
#ifdef MALI_SEC_UTILIZATION
|
||||
/*Setting gpu_active here may show real GPU utilization but it can't make full utilization(100%) */
|
||||
#else
|
||||
kbdev->pm.backend.metrics.gpu_active = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* called when job is submitted to or removed from a GPU slot */
|
||||
void kbase_pm_metrics_update(struct kbase_device *kbdev, ktime_t *timestamp)
|
||||
{
|
||||
unsigned long flags;
|
||||
ktime_t now;
|
||||
|
||||
lockdep_assert_held(&kbdev->js_data.runpool_irq.lock);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.backend.metrics.lock, flags);
|
||||
|
||||
if (!timestamp) {
|
||||
now = ktime_get();
|
||||
timestamp = &now;
|
||||
}
|
||||
|
||||
/* Track how long CL and/or GL jobs have been busy for */
|
||||
kbase_pm_get_dvfs_utilisation_calc(kbdev, *timestamp);
|
||||
|
||||
kbase_pm_metrics_active_calc(kbdev);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.backend.metrics.lock, flags);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dummy Metrics for power management.
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
|
||||
void kbase_pm_register_vsync_callback(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
/* no VSync metrics will be available */
|
||||
kbdev->pm.backend.metrics.platform_data = NULL;
|
||||
}
|
||||
|
||||
void kbase_pm_unregister_vsync_callback(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
}
|
||||
936
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_policy.c
Normal file
936
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_policy.c
Normal file
|
|
@ -0,0 +1,936 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Power policy API implementations
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <mali_kbase_gator.h>
|
||||
#include <mali_kbase_pm.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
static const struct kbase_pm_policy *const policy_list[] = {
|
||||
#ifdef CONFIG_MALI_NO_MALI
|
||||
&kbase_pm_always_on_policy_ops,
|
||||
&kbase_pm_demand_policy_ops,
|
||||
&kbase_pm_coarse_demand_policy_ops,
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
&kbase_pm_demand_always_powered_policy_ops,
|
||||
&kbase_pm_fast_start_policy_ops,
|
||||
#endif
|
||||
#else /* CONFIG_MALI_NO_MALI */
|
||||
&kbase_pm_demand_policy_ops,
|
||||
&kbase_pm_always_on_policy_ops,
|
||||
&kbase_pm_coarse_demand_policy_ops,
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
&kbase_pm_demand_always_powered_policy_ops,
|
||||
&kbase_pm_fast_start_policy_ops,
|
||||
#endif
|
||||
#endif /* CONFIG_MALI_NO_MALI */
|
||||
};
|
||||
|
||||
/* The number of policies available in the system.
|
||||
* This is derived from the number of functions listed in policy_get_functions.
|
||||
*/
|
||||
#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list))
|
||||
|
||||
|
||||
/* Function IDs for looking up Timeline Trace codes in
|
||||
* kbase_pm_change_state_trace_code */
|
||||
enum kbase_pm_func_id {
|
||||
KBASE_PM_FUNC_ID_REQUEST_CORES_START,
|
||||
KBASE_PM_FUNC_ID_REQUEST_CORES_END,
|
||||
KBASE_PM_FUNC_ID_RELEASE_CORES_START,
|
||||
KBASE_PM_FUNC_ID_RELEASE_CORES_END,
|
||||
/* Note: kbase_pm_unrequest_cores() is on the slow path, and we neither
|
||||
* expect to hit it nor tend to hit it very much anyway. We can detect
|
||||
* whether we need more instrumentation by a difference between
|
||||
* PM_CHECKTRANS events and PM_SEND/HANDLE_EVENT. */
|
||||
|
||||
/* Must be the last */
|
||||
KBASE_PM_FUNC_ID_COUNT
|
||||
};
|
||||
|
||||
|
||||
/* State changes during request/unrequest/release-ing cores */
|
||||
enum {
|
||||
KBASE_PM_CHANGE_STATE_SHADER = (1u << 0),
|
||||
KBASE_PM_CHANGE_STATE_TILER = (1u << 1),
|
||||
|
||||
/* These two must be last */
|
||||
KBASE_PM_CHANGE_STATE_MASK = (KBASE_PM_CHANGE_STATE_TILER |
|
||||
KBASE_PM_CHANGE_STATE_SHADER),
|
||||
KBASE_PM_CHANGE_STATE_COUNT = KBASE_PM_CHANGE_STATE_MASK + 1
|
||||
};
|
||||
typedef u32 kbase_pm_change_state;
|
||||
|
||||
|
||||
#ifdef CONFIG_MALI_TRACE_TIMELINE
|
||||
/* Timeline Trace code lookups for each function */
|
||||
static u32 kbase_pm_change_state_trace_code[KBASE_PM_FUNC_ID_COUNT]
|
||||
[KBASE_PM_CHANGE_STATE_COUNT] = {
|
||||
/* kbase_pm_request_cores */
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_START][0] = 0,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_SHADER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_START,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_START,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_START][KBASE_PM_CHANGE_STATE_SHADER |
|
||||
KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_START,
|
||||
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_END][0] = 0,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_SHADER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_END,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_TILER_END,
|
||||
[KBASE_PM_FUNC_ID_REQUEST_CORES_END][KBASE_PM_CHANGE_STATE_SHADER |
|
||||
KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_REQUEST_CORES_SHADER_TILER_END,
|
||||
|
||||
/* kbase_pm_release_cores */
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_START][0] = 0,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_SHADER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_START,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_START,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_START][KBASE_PM_CHANGE_STATE_SHADER |
|
||||
KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_START,
|
||||
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_END][0] = 0,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_SHADER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_END,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_TILER_END,
|
||||
[KBASE_PM_FUNC_ID_RELEASE_CORES_END][KBASE_PM_CHANGE_STATE_SHADER |
|
||||
KBASE_PM_CHANGE_STATE_TILER] =
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_SHADER_TILER_END
|
||||
};
|
||||
|
||||
static inline void kbase_timeline_pm_cores_func(struct kbase_device *kbdev,
|
||||
enum kbase_pm_func_id func_id,
|
||||
kbase_pm_change_state state)
|
||||
{
|
||||
int trace_code;
|
||||
|
||||
KBASE_DEBUG_ASSERT(func_id >= 0 && func_id < KBASE_PM_FUNC_ID_COUNT);
|
||||
KBASE_DEBUG_ASSERT(state != 0 && (state & KBASE_PM_CHANGE_STATE_MASK) ==
|
||||
state);
|
||||
|
||||
trace_code = kbase_pm_change_state_trace_code[func_id][state];
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev, trace_code);
|
||||
}
|
||||
|
||||
#else /* CONFIG_MALI_TRACE_TIMELINE */
|
||||
static inline void kbase_timeline_pm_cores_func(struct kbase_device *kbdev,
|
||||
enum kbase_pm_func_id func_id, kbase_pm_change_state state)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MALI_TRACE_TIMELINE */
|
||||
|
||||
/**
|
||||
* kbasep_pm_do_poweroff_cores - Process a poweroff request and power down any
|
||||
* requested shader cores
|
||||
* @kbdev: Device pointer
|
||||
*/
|
||||
static void kbasep_pm_do_poweroff_cores(struct kbase_device *kbdev)
|
||||
{
|
||||
u64 prev_shader_state = kbdev->pm.backend.desired_shader_state;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.power_change_lock);
|
||||
|
||||
kbdev->pm.backend.desired_shader_state &=
|
||||
~kbdev->pm.backend.shader_poweroff_pending;
|
||||
|
||||
kbdev->pm.backend.shader_poweroff_pending = 0;
|
||||
|
||||
if (prev_shader_state != kbdev->pm.backend.desired_shader_state
|
||||
|| kbdev->pm.backend.ca_in_transition) {
|
||||
bool cores_are_available;
|
||||
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_START);
|
||||
cores_are_available = kbase_pm_check_transitions_nolock(kbdev);
|
||||
KBASE_TIMELINE_PM_CHECKTRANS(kbdev,
|
||||
SW_FLOW_PM_CHECKTRANS_PM_RELEASE_CORES_DEFERRED_END);
|
||||
|
||||
/* Don't need 'cores_are_available',
|
||||
* because we don't return anything */
|
||||
CSTD_UNUSED(cores_are_available);
|
||||
}
|
||||
}
|
||||
|
||||
static enum hrtimer_restart
|
||||
kbasep_pm_do_gpu_poweroff_callback(struct hrtimer *timer)
|
||||
{
|
||||
struct kbase_device *kbdev;
|
||||
|
||||
kbdev = container_of(timer, struct kbase_device,
|
||||
pm.backend.gpu_poweroff_timer);
|
||||
|
||||
/* It is safe for this call to do nothing if the work item is already
|
||||
* queued. The worker function will read the must up-to-date state of
|
||||
* kbdev->pm.backend.gpu_poweroff_pending under lock.
|
||||
*
|
||||
* If a state change occurs while the worker function is processing,
|
||||
* this call will succeed as a work item can be requeued once it has
|
||||
* started processing.
|
||||
*/
|
||||
if (kbdev->pm.backend.gpu_poweroff_pending)
|
||||
queue_work(kbdev->pm.backend.gpu_poweroff_wq,
|
||||
&kbdev->pm.backend.gpu_poweroff_work);
|
||||
|
||||
if (kbdev->pm.backend.shader_poweroff_pending) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
if (kbdev->pm.backend.shader_poweroff_pending) {
|
||||
kbdev->pm.backend.shader_poweroff_pending_time--;
|
||||
|
||||
KBASE_DEBUG_ASSERT(
|
||||
kbdev->pm.backend.shader_poweroff_pending_time
|
||||
>= 0);
|
||||
|
||||
if (!kbdev->pm.backend.shader_poweroff_pending_time)
|
||||
kbasep_pm_do_poweroff_cores(kbdev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
if (kbdev->pm.backend.poweroff_timer_needed) {
|
||||
hrtimer_add_expires(timer, kbdev->pm.gpu_poweroff_time);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static void kbasep_pm_do_gpu_poweroff_wq(struct work_struct *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct kbase_device *kbdev;
|
||||
bool do_poweroff = false;
|
||||
|
||||
kbdev = container_of(data, struct kbase_device,
|
||||
pm.backend.gpu_poweroff_work);
|
||||
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
|
||||
if (kbdev->pm.backend.gpu_poweroff_pending == 0) {
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
kbdev->pm.backend.gpu_poweroff_pending--;
|
||||
|
||||
if (kbdev->pm.backend.gpu_poweroff_pending > 0) {
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_poweroff_pending == 0);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
/* Only power off the GPU if a request is still pending */
|
||||
if (!kbdev->pm.backend.pm_current_policy->get_core_active(kbdev))
|
||||
do_poweroff = true;
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
if (do_poweroff) {
|
||||
kbdev->pm.backend.poweroff_timer_needed = false;
|
||||
hrtimer_cancel(&kbdev->pm.backend.gpu_poweroff_timer);
|
||||
/* Power off the GPU */
|
||||
if (!kbase_pm_do_poweroff(kbdev, false)) {
|
||||
/* GPU can not be powered off at present */
|
||||
kbdev->pm.backend.poweroff_timer_needed = true;
|
||||
hrtimer_start(&kbdev->pm.backend.gpu_poweroff_timer,
|
||||
kbdev->pm.gpu_poweroff_time,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
}
|
||||
|
||||
int kbase_pm_policy_init(struct kbase_device *kbdev)
|
||||
{
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
wq = alloc_workqueue("kbase_pm_do_poweroff",
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
// WQ_HIGHPRI | WQ_UNBOUND, 1);
|
||||
WQ_HIGHPRI , 1);
|
||||
if (!wq)
|
||||
return -ENOMEM;
|
||||
|
||||
kbdev->pm.backend.gpu_poweroff_wq = wq;
|
||||
INIT_WORK(&kbdev->pm.backend.gpu_poweroff_work,
|
||||
kbasep_pm_do_gpu_poweroff_wq);
|
||||
hrtimer_init(&kbdev->pm.backend.gpu_poweroff_timer,
|
||||
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
kbdev->pm.backend.gpu_poweroff_timer.function =
|
||||
kbasep_pm_do_gpu_poweroff_callback;
|
||||
kbdev->pm.backend.pm_current_policy = policy_list[2];
|
||||
kbdev->pm.backend.pm_current_policy->init(kbdev);
|
||||
kbdev->pm.gpu_poweroff_time =
|
||||
HR_TIMER_DELAY_NSEC(DEFAULT_PM_GPU_POWEROFF_TICK_NS);
|
||||
kbdev->pm.poweroff_shader_ticks = DEFAULT_PM_POWEROFF_TICK_SHADER;
|
||||
kbdev->pm.poweroff_gpu_ticks = DEFAULT_PM_POWEROFF_TICK_GPU;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbase_pm_policy_term(struct kbase_device *kbdev)
|
||||
{
|
||||
kbdev->pm.backend.pm_current_policy->term(kbdev);
|
||||
destroy_workqueue(kbdev->pm.backend.gpu_poweroff_wq);
|
||||
}
|
||||
|
||||
void kbase_pm_cancel_deferred_poweroff(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.lock);
|
||||
|
||||
kbdev->pm.backend.poweroff_timer_needed = false;
|
||||
hrtimer_cancel(&kbdev->pm.backend.gpu_poweroff_timer);
|
||||
|
||||
/* If wq is already running but is held off by pm.lock, make sure it has
|
||||
* no effect */
|
||||
kbdev->pm.backend.gpu_poweroff_pending = 0;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
kbdev->pm.backend.shader_poweroff_pending = 0;
|
||||
kbdev->pm.backend.shader_poweroff_pending_time = 0;
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
void kbase_pm_update_active(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
bool active;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.lock);
|
||||
|
||||
/* pm_current_policy will never be NULL while pm.lock is held */
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.backend.pm_current_policy);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
active = kbdev->pm.backend.pm_current_policy->get_core_active(kbdev);
|
||||
|
||||
if (active) {
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
if (kbdev->pm.backend.gpu_poweroff_pending) {
|
||||
/* Cancel any pending power off request */
|
||||
kbdev->pm.backend.gpu_poweroff_pending = 0;
|
||||
|
||||
/* If a request was pending then the GPU was still
|
||||
* powered, so no need to continue */
|
||||
if (!kbdev->poweroff_pending)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!kbdev->pm.backend.poweroff_timer_needed &&
|
||||
!kbdev->pm.backend.gpu_powered &&
|
||||
(kbdev->pm.poweroff_gpu_ticks ||
|
||||
kbdev->pm.poweroff_shader_ticks)) {
|
||||
kbdev->pm.backend.poweroff_timer_needed = true;
|
||||
hrtimer_start(&kbdev->pm.backend.gpu_poweroff_timer,
|
||||
kbdev->pm.gpu_poweroff_time,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
/* Power on the GPU and any cores requested by the policy */
|
||||
kbase_pm_do_poweron(kbdev, false);
|
||||
} else {
|
||||
/* It is an error for the power policy to power off the GPU
|
||||
* when there are contexts active */
|
||||
KBASE_DEBUG_ASSERT(kbdev->pm.active_count == 0);
|
||||
|
||||
if (kbdev->pm.backend.shader_poweroff_pending) {
|
||||
kbdev->pm.backend.shader_poweroff_pending = 0;
|
||||
kbdev->pm.backend.shader_poweroff_pending_time = 0;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
|
||||
/* Request power off */
|
||||
if (kbdev->pm.backend.gpu_powered) {
|
||||
if (kbdev->pm.poweroff_gpu_ticks) {
|
||||
kbdev->pm.backend.gpu_poweroff_pending =
|
||||
kbdev->pm.poweroff_gpu_ticks;
|
||||
if (!kbdev->pm.backend.poweroff_timer_needed) {
|
||||
/* Start timer if not running (eg if
|
||||
* power policy has been changed from
|
||||
* always_on to something else). This
|
||||
* will ensure the GPU is actually
|
||||
* powered off */
|
||||
kbdev->pm.backend.poweroff_timer_needed
|
||||
= true;
|
||||
hrtimer_start(
|
||||
&kbdev->pm.backend.gpu_poweroff_timer,
|
||||
kbdev->pm.gpu_poweroff_time,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
} else {
|
||||
/* Power off the GPU immediately */
|
||||
if (!kbase_pm_do_poweroff(kbdev, false)) {
|
||||
/* GPU can not be powered off at present
|
||||
*/
|
||||
kbdev->pm.backend.poweroff_timer_needed
|
||||
= true;
|
||||
hrtimer_start(
|
||||
&kbdev->pm.backend.gpu_poweroff_timer,
|
||||
kbdev->pm.gpu_poweroff_time,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_pm_update_cores_state_nolock(struct kbase_device *kbdev)
|
||||
{
|
||||
u64 desired_bitmap;
|
||||
bool cores_are_available;
|
||||
bool do_poweroff = false;
|
||||
|
||||
lockdep_assert_held(&kbdev->pm.power_change_lock);
|
||||
|
||||
if (kbdev->pm.backend.pm_current_policy == NULL)
|
||||
return;
|
||||
|
||||
desired_bitmap =
|
||||
kbdev->pm.backend.pm_current_policy->get_core_mask(kbdev);
|
||||
desired_bitmap &= kbase_pm_ca_get_core_mask(kbdev);
|
||||
|
||||
/* Enable core 0 if tiler required, regardless of core availability */
|
||||
if (kbdev->tiler_needed_cnt > 0 || kbdev->tiler_inuse_cnt > 0)
|
||||
desired_bitmap |= 1;
|
||||
|
||||
if (kbdev->pm.backend.desired_shader_state != desired_bitmap)
|
||||
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_DESIRED, NULL, NULL, 0u,
|
||||
(u32)desired_bitmap);
|
||||
/* Are any cores being powered on? */
|
||||
if (~kbdev->pm.backend.desired_shader_state & desired_bitmap ||
|
||||
kbdev->pm.backend.ca_in_transition) {
|
||||
/* Check if we are powering off any cores before updating shader
|
||||
* state */
|
||||
if (kbdev->pm.backend.desired_shader_state & ~desired_bitmap) {
|
||||
/* Start timer to power off cores */
|
||||
kbdev->pm.backend.shader_poweroff_pending |=
|
||||
(kbdev->pm.backend.desired_shader_state &
|
||||
~desired_bitmap);
|
||||
|
||||
if (kbdev->pm.poweroff_shader_ticks)
|
||||
kbdev->pm.backend.shader_poweroff_pending_time =
|
||||
kbdev->pm.poweroff_shader_ticks;
|
||||
else
|
||||
do_poweroff = true;
|
||||
}
|
||||
|
||||
kbdev->pm.backend.desired_shader_state = desired_bitmap;
|
||||
|
||||
/* If any cores are being powered on, transition immediately */
|
||||
cores_are_available = kbase_pm_check_transitions_nolock(kbdev);
|
||||
} else if (kbdev->pm.backend.desired_shader_state & ~desired_bitmap) {
|
||||
/* Start timer to power off cores */
|
||||
kbdev->pm.backend.shader_poweroff_pending |=
|
||||
(kbdev->pm.backend.desired_shader_state &
|
||||
~desired_bitmap);
|
||||
if (kbdev->pm.poweroff_shader_ticks)
|
||||
kbdev->pm.backend.shader_poweroff_pending_time =
|
||||
kbdev->pm.poweroff_shader_ticks;
|
||||
else
|
||||
kbasep_pm_do_poweroff_cores(kbdev);
|
||||
} else if (kbdev->pm.active_count == 0 && desired_bitmap != 0 &&
|
||||
kbdev->pm.backend.poweroff_timer_needed) {
|
||||
/* If power policy is keeping cores on despite there being no
|
||||
* active contexts then disable poweroff timer as it isn't
|
||||
* required.
|
||||
* Only reset poweroff_timer_needed if we're not in the middle
|
||||
* of the power off callback */
|
||||
kbdev->pm.backend.poweroff_timer_needed = false;
|
||||
hrtimer_try_to_cancel(&kbdev->pm.backend.gpu_poweroff_timer);
|
||||
}
|
||||
|
||||
/* Ensure timer does not power off wanted cores and make sure to power
|
||||
* off unwanted cores */
|
||||
if (kbdev->pm.backend.shader_poweroff_pending != 0) {
|
||||
kbdev->pm.backend.shader_poweroff_pending &=
|
||||
~(kbdev->pm.backend.desired_shader_state &
|
||||
desired_bitmap);
|
||||
if (kbdev->pm.backend.shader_poweroff_pending == 0)
|
||||
kbdev->pm.backend.shader_poweroff_pending_time = 0;
|
||||
}
|
||||
|
||||
/* Shader poweroff is deferred to the end of the function, to eliminate
|
||||
* issues caused by the core availability policy recursing into this
|
||||
* function */
|
||||
if (do_poweroff)
|
||||
kbasep_pm_do_poweroff_cores(kbdev);
|
||||
|
||||
/* Don't need 'cores_are_available', because we don't return anything */
|
||||
CSTD_UNUSED(cores_are_available);
|
||||
}
|
||||
|
||||
void kbase_pm_update_cores_state(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
int kbase_pm_list_policies(const struct kbase_pm_policy * const **list)
|
||||
{
|
||||
if (!list)
|
||||
return POLICY_COUNT;
|
||||
|
||||
*list = policy_list;
|
||||
|
||||
return POLICY_COUNT;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_list_policies);
|
||||
|
||||
const struct kbase_pm_policy *kbase_pm_get_policy(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
return kbdev->pm.backend.pm_current_policy;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_get_policy);
|
||||
|
||||
void kbase_pm_set_policy(struct kbase_device *kbdev,
|
||||
const struct kbase_pm_policy *new_policy)
|
||||
{
|
||||
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
|
||||
const struct kbase_pm_policy *old_policy;
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(new_policy != NULL);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, PM_SET_POLICY, NULL, NULL, 0u, new_policy->id);
|
||||
|
||||
/* During a policy change we pretend the GPU is active */
|
||||
/* A suspend won't happen here, because we're in a syscall from a
|
||||
* userspace thread */
|
||||
kbase_pm_context_active(kbdev);
|
||||
|
||||
mutex_lock(&js_devdata->runpool_mutex);
|
||||
mutex_lock(&kbdev->pm.lock);
|
||||
|
||||
/* Remove the policy to prevent IRQ handlers from working on it */
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
old_policy = kbdev->pm.backend.pm_current_policy;
|
||||
kbdev->pm.backend.pm_current_policy = NULL;
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, PM_CURRENT_POLICY_TERM, NULL, NULL, 0u,
|
||||
old_policy->id);
|
||||
if (old_policy->term)
|
||||
old_policy->term(kbdev);
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, PM_CURRENT_POLICY_INIT, NULL, NULL, 0u,
|
||||
new_policy->id);
|
||||
if (new_policy->init)
|
||||
new_policy->init(kbdev);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
kbdev->pm.backend.pm_current_policy = new_policy;
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
/* If any core power state changes were previously attempted, but
|
||||
* couldn't be made because the policy was changing (current_policy was
|
||||
* NULL), then re-try them here. */
|
||||
kbase_pm_update_active(kbdev);
|
||||
kbase_pm_update_cores_state(kbdev);
|
||||
|
||||
mutex_unlock(&kbdev->pm.lock);
|
||||
mutex_unlock(&js_devdata->runpool_mutex);
|
||||
|
||||
/* Now the policy change is finished, we release our fake context active
|
||||
* reference */
|
||||
kbase_pm_context_idle(kbdev);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_set_policy);
|
||||
|
||||
/* Check whether a state change has finished, and trace it as completed */
|
||||
static void
|
||||
kbase_pm_trace_check_and_finish_state_change(struct kbase_device *kbdev)
|
||||
{
|
||||
if ((kbdev->shader_available_bitmap &
|
||||
kbdev->pm.backend.desired_shader_state)
|
||||
== kbdev->pm.backend.desired_shader_state &&
|
||||
(kbdev->tiler_available_bitmap &
|
||||
kbdev->pm.backend.desired_tiler_state)
|
||||
== kbdev->pm.backend.desired_tiler_state)
|
||||
kbase_timeline_pm_check_handle_event(kbdev,
|
||||
KBASE_TIMELINE_PM_EVENT_GPU_STATE_CHANGED);
|
||||
}
|
||||
|
||||
void kbase_pm_request_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 cores;
|
||||
|
||||
kbase_pm_change_state change_gpu_state = 0u;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
cores = shader_cores;
|
||||
while (cores) {
|
||||
int bitnum = fls64(cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
|
||||
/* It should be almost impossible for this to overflow. It would
|
||||
* require 2^32 atoms to request a particular core, which would
|
||||
* require 2^24 contexts to submit. This would require an amount
|
||||
* of memory that is impossible on a 32-bit system and extremely
|
||||
* unlikely on a 64-bit system. */
|
||||
int cnt = ++kbdev->shader_needed_cnt[bitnum];
|
||||
|
||||
if (1 == cnt) {
|
||||
kbdev->shader_needed_bitmap |= bit;
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER;
|
||||
}
|
||||
|
||||
cores &= ~bit;
|
||||
}
|
||||
|
||||
if (tiler_required) {
|
||||
int cnt = ++kbdev->tiler_needed_cnt;
|
||||
|
||||
if (1 == cnt)
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt != 0);
|
||||
}
|
||||
|
||||
if (change_gpu_state) {
|
||||
KBASE_TRACE_ADD(kbdev, PM_REQUEST_CHANGE_SHADER_NEEDED, NULL,
|
||||
NULL, 0u, (u32) kbdev->shader_needed_bitmap);
|
||||
|
||||
kbase_timeline_pm_cores_func(kbdev,
|
||||
KBASE_PM_FUNC_ID_REQUEST_CORES_START,
|
||||
change_gpu_state);
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
kbase_timeline_pm_cores_func(kbdev,
|
||||
KBASE_PM_FUNC_ID_REQUEST_CORES_END,
|
||||
change_gpu_state);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_request_cores);
|
||||
|
||||
void kbase_pm_unrequest_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
kbase_pm_change_state change_gpu_state = 0u;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
while (shader_cores) {
|
||||
int bitnum = fls64(shader_cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
int cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0);
|
||||
|
||||
cnt = --kbdev->shader_needed_cnt[bitnum];
|
||||
|
||||
if (0 == cnt) {
|
||||
kbdev->shader_needed_bitmap &= ~bit;
|
||||
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER;
|
||||
}
|
||||
|
||||
shader_cores &= ~bit;
|
||||
}
|
||||
|
||||
if (tiler_required) {
|
||||
int cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt > 0);
|
||||
|
||||
cnt = --kbdev->tiler_needed_cnt;
|
||||
|
||||
if (0 == cnt)
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER;
|
||||
}
|
||||
|
||||
if (change_gpu_state) {
|
||||
KBASE_TRACE_ADD(kbdev, PM_UNREQUEST_CHANGE_SHADER_NEEDED, NULL,
|
||||
NULL, 0u, (u32) kbdev->shader_needed_bitmap);
|
||||
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
|
||||
/* Trace that any state change effectively completes immediately
|
||||
* - no-one will wait on the state change */
|
||||
kbase_pm_trace_check_and_finish_state_change(kbdev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_unrequest_cores);
|
||||
|
||||
enum kbase_pm_cores_ready
|
||||
kbase_pm_register_inuse_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 prev_shader_needed; /* Just for tracing */
|
||||
u64 prev_shader_inuse; /* Just for tracing */
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
prev_shader_needed = kbdev->shader_needed_bitmap;
|
||||
prev_shader_inuse = kbdev->shader_inuse_bitmap;
|
||||
|
||||
/* If desired_shader_state does not contain the requested cores, then
|
||||
* power management is not attempting to powering those cores (most
|
||||
* likely due to core availability policy) and a new job affinity must
|
||||
* be chosen */
|
||||
if ((kbdev->pm.backend.desired_shader_state & shader_cores) !=
|
||||
shader_cores) {
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
return KBASE_NEW_AFFINITY;
|
||||
}
|
||||
|
||||
if ((kbdev->shader_available_bitmap & shader_cores) != shader_cores ||
|
||||
(tiler_required && !kbdev->tiler_available_bitmap)) {
|
||||
/* Trace ongoing core transition */
|
||||
kbase_timeline_pm_l2_transition_start(kbdev);
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
return KBASE_CORES_NOT_READY;
|
||||
}
|
||||
|
||||
/* If we started to trace a state change, then trace it has being
|
||||
* finished by now, at the very latest */
|
||||
kbase_pm_trace_check_and_finish_state_change(kbdev);
|
||||
/* Trace core transition done */
|
||||
kbase_timeline_pm_l2_transition_done(kbdev);
|
||||
|
||||
while (shader_cores) {
|
||||
int bitnum = fls64(shader_cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
int cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->shader_needed_cnt[bitnum] > 0);
|
||||
|
||||
cnt = --kbdev->shader_needed_cnt[bitnum];
|
||||
|
||||
if (0 == cnt)
|
||||
kbdev->shader_needed_bitmap &= ~bit;
|
||||
|
||||
/* shader_inuse_cnt should not overflow because there can only
|
||||
* be a very limited number of jobs on the h/w at one time */
|
||||
|
||||
kbdev->shader_inuse_cnt[bitnum]++;
|
||||
kbdev->shader_inuse_bitmap |= bit;
|
||||
|
||||
shader_cores &= ~bit;
|
||||
}
|
||||
|
||||
if (tiler_required) {
|
||||
KBASE_DEBUG_ASSERT(kbdev->tiler_needed_cnt > 0);
|
||||
|
||||
--kbdev->tiler_needed_cnt;
|
||||
|
||||
kbdev->tiler_inuse_cnt++;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->tiler_inuse_cnt != 0);
|
||||
}
|
||||
|
||||
if (prev_shader_needed != kbdev->shader_needed_bitmap)
|
||||
KBASE_TRACE_ADD(kbdev, PM_REGISTER_CHANGE_SHADER_NEEDED, NULL,
|
||||
NULL, 0u, (u32) kbdev->shader_needed_bitmap);
|
||||
|
||||
if (prev_shader_inuse != kbdev->shader_inuse_bitmap)
|
||||
KBASE_TRACE_ADD(kbdev, PM_REGISTER_CHANGE_SHADER_INUSE, NULL,
|
||||
NULL, 0u, (u32) kbdev->shader_inuse_bitmap);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
return KBASE_CORES_READY;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_register_inuse_cores);
|
||||
|
||||
void kbase_pm_release_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores)
|
||||
{
|
||||
unsigned long flags;
|
||||
kbase_pm_change_state change_gpu_state = 0u;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
while (shader_cores) {
|
||||
int bitnum = fls64(shader_cores) - 1;
|
||||
u64 bit = 1ULL << bitnum;
|
||||
int cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->shader_inuse_cnt[bitnum] > 0);
|
||||
|
||||
cnt = --kbdev->shader_inuse_cnt[bitnum];
|
||||
|
||||
if (0 == cnt) {
|
||||
kbdev->shader_inuse_bitmap &= ~bit;
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_SHADER;
|
||||
}
|
||||
|
||||
shader_cores &= ~bit;
|
||||
}
|
||||
|
||||
if (tiler_required) {
|
||||
int cnt;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->tiler_inuse_cnt > 0);
|
||||
|
||||
cnt = --kbdev->tiler_inuse_cnt;
|
||||
|
||||
if (0 == cnt)
|
||||
change_gpu_state |= KBASE_PM_CHANGE_STATE_TILER;
|
||||
}
|
||||
|
||||
if (change_gpu_state) {
|
||||
KBASE_TRACE_ADD(kbdev, PM_RELEASE_CHANGE_SHADER_INUSE, NULL,
|
||||
NULL, 0u, (u32) kbdev->shader_inuse_bitmap);
|
||||
|
||||
kbase_timeline_pm_cores_func(kbdev,
|
||||
KBASE_PM_FUNC_ID_RELEASE_CORES_START,
|
||||
change_gpu_state);
|
||||
kbase_pm_update_cores_state_nolock(kbdev);
|
||||
kbase_timeline_pm_cores_func(kbdev,
|
||||
KBASE_PM_FUNC_ID_RELEASE_CORES_END,
|
||||
change_gpu_state);
|
||||
|
||||
/* Trace that any state change completed immediately */
|
||||
kbase_pm_trace_check_and_finish_state_change(kbdev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_release_cores);
|
||||
|
||||
void kbase_pm_request_cores_sync(struct kbase_device *kbdev,
|
||||
bool tiler_required,
|
||||
u64 shader_cores)
|
||||
{
|
||||
kbase_pm_request_cores(kbdev, tiler_required, shader_cores);
|
||||
|
||||
kbase_pm_check_transitions_sync(kbdev);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_request_cores_sync);
|
||||
|
||||
void kbase_pm_request_l2_caches(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 prior_l2_users_count;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
prior_l2_users_count = kbdev->l2_users_count++;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->l2_users_count != 0);
|
||||
|
||||
/* if the GPU is reset while the l2 is on, l2 will be off but
|
||||
* prior_l2_users_count will be > 0. l2_available_bitmap will have been
|
||||
* set to 0 though by kbase_pm_init_hw */
|
||||
if (!prior_l2_users_count || !kbdev->l2_available_bitmap)
|
||||
kbase_pm_check_transitions_nolock(kbdev);
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
wait_event(kbdev->pm.backend.l2_powered_wait,
|
||||
kbdev->pm.backend.l2_powered == 1);
|
||||
|
||||
/* Trace that any state change completed immediately */
|
||||
kbase_pm_trace_check_and_finish_state_change(kbdev);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_request_l2_caches);
|
||||
|
||||
void kbase_pm_request_l2_caches_l2_is_on(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
kbdev->l2_users_count++;
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_request_l2_caches_l2_is_on);
|
||||
|
||||
void kbase_pm_release_l2_caches(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev->l2_users_count > 0);
|
||||
|
||||
--kbdev->l2_users_count;
|
||||
|
||||
if (!kbdev->l2_users_count) {
|
||||
kbase_pm_check_transitions_nolock(kbdev);
|
||||
/* Trace that any state change completed immediately */
|
||||
kbase_pm_trace_check_and_finish_state_change(kbdev);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_pm_release_l2_caches);
|
||||
227
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_policy.h
Normal file
227
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_pm_policy.h
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Power policy API definitions
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_PM_POLICY_H_
|
||||
#define _KBASE_PM_POLICY_H_
|
||||
|
||||
/**
|
||||
* kbase_pm_policy_init - Initialize power policy framework
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Must be called before calling any other policy function
|
||||
*
|
||||
* Return: 0 if the power policy framework was successfully
|
||||
* initialized, -errno otherwise.
|
||||
*/
|
||||
int kbase_pm_policy_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_policy_term - Terminate power policy framework
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*/
|
||||
void kbase_pm_policy_term(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_update_active - Update the active power state of the GPU
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Calls into the current power policy
|
||||
*/
|
||||
void kbase_pm_update_active(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_update_cores - Update the desired core state of the GPU
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Calls into the current power policy
|
||||
*/
|
||||
void kbase_pm_update_cores(struct kbase_device *kbdev);
|
||||
|
||||
|
||||
enum kbase_pm_cores_ready {
|
||||
KBASE_CORES_NOT_READY = 0,
|
||||
KBASE_NEW_AFFINITY = 1,
|
||||
KBASE_CORES_READY = 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* kbase_pm_request_cores_sync - Synchronous variant of kbase_pm_request_cores()
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* @tiler_required: true if the tiler is required, false otherwise
|
||||
* @shader_cores: A bitmask of shader cores which are necessary for the job
|
||||
*
|
||||
* When this function returns, the @shader_cores will be in the READY state.
|
||||
*
|
||||
* This is safe variant of kbase_pm_check_transitions_sync(): it handles the
|
||||
* work of ensuring the requested cores will remain powered until a matching
|
||||
* call to kbase_pm_unrequest_cores()/kbase_pm_release_cores() (as appropriate)
|
||||
* is made.
|
||||
*/
|
||||
void kbase_pm_request_cores_sync(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_cores - Mark one or more cores as being required
|
||||
* for jobs to be submitted
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* @tiler_required: true if the tiler is required, false otherwise
|
||||
* @shader_cores: A bitmask of shader cores which are necessary for the job
|
||||
*
|
||||
* This function is called by the job scheduler to mark one or more cores as
|
||||
* being required to submit jobs that are ready to run.
|
||||
*
|
||||
* The cores requested are reference counted and a subsequent call to
|
||||
* kbase_pm_register_inuse_cores() or kbase_pm_unrequest_cores() should be
|
||||
* made to dereference the cores as being 'needed'.
|
||||
*
|
||||
* The active power policy will meet or exceed the requirements of the
|
||||
* requested cores in the system. Any core transitions needed will be begun
|
||||
* immediately, but they might not complete/the cores might not be available
|
||||
* until a Power Management IRQ.
|
||||
*
|
||||
* Return: 0 if the cores were successfully requested, or -errno otherwise.
|
||||
*/
|
||||
void kbase_pm_request_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores);
|
||||
|
||||
/**
|
||||
* kbase_pm_unrequest_cores - Unmark one or more cores as being required for
|
||||
* jobs to be submitted.
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* @tiler_required: true if the tiler is required, false otherwise
|
||||
* @shader_cores: A bitmask of shader cores (as given to
|
||||
* kbase_pm_request_cores() )
|
||||
*
|
||||
* This function undoes the effect of kbase_pm_request_cores(). It should be
|
||||
* used when a job is not going to be submitted to the hardware (e.g. the job is
|
||||
* cancelled before it is enqueued).
|
||||
*
|
||||
* The active power policy will meet or exceed the requirements of the
|
||||
* requested cores in the system. Any core transitions needed will be begun
|
||||
* immediately, but they might not complete until a Power Management IRQ.
|
||||
*
|
||||
* The policy may use this as an indication that it can power down cores.
|
||||
*/
|
||||
void kbase_pm_unrequest_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores);
|
||||
|
||||
/**
|
||||
* kbase_pm_register_inuse_cores - Register a set of cores as in use by a job
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* @tiler_required: true if the tiler is required, false otherwise
|
||||
* @shader_cores: A bitmask of shader cores (as given to
|
||||
* kbase_pm_request_cores() )
|
||||
*
|
||||
* This function should be called after kbase_pm_request_cores() when the job
|
||||
* is about to be submitted to the hardware. It will check that the necessary
|
||||
* cores are available and if so update the 'needed' and 'inuse' bitmasks to
|
||||
* reflect that the job is now committed to being run.
|
||||
*
|
||||
* If the necessary cores are not currently available then the function will
|
||||
* return %KBASE_CORES_NOT_READY and have no effect.
|
||||
*
|
||||
* Return: %KBASE_CORES_NOT_READY if the cores are not immediately ready,
|
||||
*
|
||||
* %KBASE_NEW_AFFINITY if the affinity requested is not allowed,
|
||||
*
|
||||
* %KBASE_CORES_READY if the cores requested are already available
|
||||
*/
|
||||
enum kbase_pm_cores_ready kbase_pm_register_inuse_cores(
|
||||
struct kbase_device *kbdev,
|
||||
bool tiler_required,
|
||||
u64 shader_cores);
|
||||
|
||||
/**
|
||||
* kbase_pm_release_cores - Release cores after a job has run
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device
|
||||
* @tiler_required: true if the tiler is required, false otherwise
|
||||
* @shader_cores: A bitmask of shader cores (as given to
|
||||
* kbase_pm_register_inuse_cores() )
|
||||
*
|
||||
* This function should be called when a job has finished running on the
|
||||
* hardware. A call to kbase_pm_register_inuse_cores() must have previously
|
||||
* occurred. The reference counts of the specified cores will be decremented
|
||||
* which may cause the bitmask of 'inuse' cores to be reduced. The power policy
|
||||
* may then turn off any cores which are no longer 'inuse'.
|
||||
*/
|
||||
void kbase_pm_release_cores(struct kbase_device *kbdev,
|
||||
bool tiler_required, u64 shader_cores);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_l2_caches - Request l2 caches
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Request the use of l2 caches for all core groups, power up, wait and prevent
|
||||
* the power manager from powering down the l2 caches.
|
||||
*
|
||||
* This tells the power management that the caches should be powered up, and
|
||||
* they should remain powered, irrespective of the usage of shader cores. This
|
||||
* does not return until the l2 caches are powered up.
|
||||
*
|
||||
* The caller must call kbase_pm_release_l2_caches() when they are finished
|
||||
* to allow normal power management of the l2 caches to resume.
|
||||
*
|
||||
* This should only be used when power management is active.
|
||||
*/
|
||||
void kbase_pm_request_l2_caches(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_l2_caches_l2_is_on - Request l2 caches but don't power on
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Increment the count of l2 users but do not attempt to power on the l2
|
||||
*
|
||||
* It is the callers responsibility to ensure that the l2 is already powered up
|
||||
* and to eventually call kbase_pm_release_l2_caches()
|
||||
*/
|
||||
void kbase_pm_request_l2_caches_l2_is_on(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_pm_request_l2_caches - Release l2 caches
|
||||
*
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
*
|
||||
* Release the use of l2 caches for all core groups and allow the power manager
|
||||
* to power them down when necessary.
|
||||
*
|
||||
* This tells the power management that the caches can be powered down if
|
||||
* necessary, with respect to the usage of shader cores.
|
||||
*
|
||||
* The caller must have called kbase_pm_request_l2_caches() prior to a call
|
||||
* to this.
|
||||
*
|
||||
* This should only be used when power management is active.
|
||||
*/
|
||||
void kbase_pm_release_l2_caches(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_PM_POLICY_H_ */
|
||||
102
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_time.c
Normal file
102
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_time.c
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <mali_kbase_hwaccess_time.h>
|
||||
#include <backend/gpu/mali_kbase_device_internal.h>
|
||||
#include <backend/gpu/mali_kbase_pm_internal.h>
|
||||
|
||||
void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter,
|
||||
u64 *system_time, struct timespec *ts)
|
||||
{
|
||||
u32 hi1, hi2;
|
||||
|
||||
kbase_pm_request_gpu_cycle_counter(kbdev);
|
||||
|
||||
/* Read hi, lo, hi to ensure that overflow from lo to hi is handled
|
||||
* correctly */
|
||||
do {
|
||||
hi1 = kbase_reg_read(kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI),
|
||||
NULL);
|
||||
*cycle_counter = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL);
|
||||
hi2 = kbase_reg_read(kbdev, GPU_CONTROL_REG(CYCLE_COUNT_HI),
|
||||
NULL);
|
||||
*cycle_counter |= (((u64) hi1) << 32);
|
||||
} while (hi1 != hi2);
|
||||
|
||||
/* Read hi, lo, hi to ensure that overflow from lo to hi is handled
|
||||
* correctly */
|
||||
do {
|
||||
hi1 = kbase_reg_read(kbdev, GPU_CONTROL_REG(TIMESTAMP_HI),
|
||||
NULL);
|
||||
*system_time = kbase_reg_read(kbdev,
|
||||
GPU_CONTROL_REG(TIMESTAMP_LO), NULL);
|
||||
hi2 = kbase_reg_read(kbdev, GPU_CONTROL_REG(TIMESTAMP_HI),
|
||||
NULL);
|
||||
*system_time |= (((u64) hi1) << 32);
|
||||
} while (hi1 != hi2);
|
||||
|
||||
/* Record the CPU's idea of current time */
|
||||
getrawmonotonic(ts);
|
||||
|
||||
kbase_pm_release_gpu_cycle_counter(kbdev);
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_wait_write_flush - Wait for GPU write flush
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush
|
||||
* its write buffer.
|
||||
*
|
||||
* Only in use for BASE_HW_ISSUE_6367
|
||||
*
|
||||
* Note : If GPU resets occur then the counters are reset to zero, the delay may
|
||||
* not be as expected.
|
||||
*/
|
||||
#ifndef CONFIG_MALI_NO_MALI
|
||||
void kbase_wait_write_flush(struct kbase_context *kctx)
|
||||
{
|
||||
u32 base_count = 0;
|
||||
|
||||
/* A suspend won't happen here, because we're in a syscall from a
|
||||
* userspace thread */
|
||||
|
||||
kbase_pm_context_active(kctx->kbdev);
|
||||
kbase_pm_request_gpu_cycle_counter(kctx->kbdev);
|
||||
|
||||
while (true) {
|
||||
u32 new_count;
|
||||
|
||||
new_count = kbase_reg_read(kctx->kbdev,
|
||||
GPU_CONTROL_REG(CYCLE_COUNT_LO), NULL);
|
||||
/* First time around, just store the count. */
|
||||
if (base_count == 0) {
|
||||
base_count = new_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No need to handle wrapping, unsigned maths works for this. */
|
||||
if ((new_count - base_count) > 1000)
|
||||
break;
|
||||
}
|
||||
|
||||
kbase_pm_release_gpu_cycle_counter(kctx->kbdev);
|
||||
kbase_pm_context_idle(kctx->kbdev);
|
||||
}
|
||||
#endif /* CONFIG_MALI_NO_MALI */
|
||||
52
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_time.h
Normal file
52
drivers/gpu/arm/t72x/r7p0/backend/gpu/mali_kbase_time.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_BACKEND_TIME_H_
|
||||
#define _KBASE_BACKEND_TIME_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_get_gpu_time() - Get current GPU time
|
||||
* @kbdev: Device pointer
|
||||
* @cycle_counter: Pointer to u64 to store cycle counter in
|
||||
* @system_time: Pointer to u64 to store system time in
|
||||
* @ts: Pointer to struct timespec to store current monotonic
|
||||
* time in
|
||||
*/
|
||||
void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter,
|
||||
u64 *system_time, struct timespec *ts);
|
||||
|
||||
/**
|
||||
* kbase_wait_write_flush() - Wait for GPU write flush
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush
|
||||
* its write buffer.
|
||||
*
|
||||
* If GPU resets occur then the counters are reset to zero, the delay may not be
|
||||
* as expected.
|
||||
*
|
||||
* This function is only in use for BASE_HW_ISSUE_6367
|
||||
*/
|
||||
#ifdef CONFIG_MALI_NO_MALI
|
||||
static inline void kbase_wait_write_flush(struct kbase_context *kctx)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void kbase_wait_write_flush(struct kbase_context *kctx);
|
||||
#endif
|
||||
|
||||
#endif /* _KBASE_BACKEND_TIME_H_ */
|
||||
63
drivers/gpu/arm/t72x/r7p0/docs/policy_overview.dot
Normal file
63
drivers/gpu/arm/t72x/r7p0/docs/policy_overview.dot
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
digraph policy_objects_diagram {
|
||||
rankdir=LR
|
||||
size="6,6"
|
||||
compound=true;
|
||||
|
||||
node [ shape = box ];
|
||||
|
||||
call_enqueue [ shape=plaintext label="enqueue ctx" ];
|
||||
|
||||
|
||||
policy_queue [ label="Policy's Queue" ];
|
||||
|
||||
{
|
||||
rank=same;
|
||||
runpool [ label="Policy's Run Pool" ];
|
||||
|
||||
ctx_finish [ label="ctx finished" ];
|
||||
}
|
||||
|
||||
{
|
||||
rank=same;
|
||||
jobslots [ shape=record label="Jobslots: | <0>js[0] | <1>js[1] | <2>js[2]" ];
|
||||
|
||||
job_finish [ label="Job finished" ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Edges
|
||||
*/
|
||||
|
||||
call_enqueue -> policy_queue;
|
||||
|
||||
policy_queue->runpool [label="dequeue ctx" weight=0.1];
|
||||
runpool->policy_queue [label="requeue ctx" weight=0.1];
|
||||
|
||||
runpool->ctx_finish [ style=dotted ];
|
||||
|
||||
runpool->jobslots [label="dequeue job" weight=0.1];
|
||||
jobslots->runpool [label="requeue job" weight=0.1];
|
||||
|
||||
jobslots->job_finish [ style=dotted ];
|
||||
}
|
||||
192
drivers/gpu/arm/t72x/r7p0/mali_base_hwconfig_features.h
Normal file
192
drivers/gpu/arm/t72x/r7p0/mali_base_hwconfig_features.h
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* AUTOMATICALLY GENERATED FILE. If you want to amend the issues/features,
|
||||
* please update base/tools/hwconfig_generator/hwc_{issues,features}.py
|
||||
* For more information see base/tools/hwconfig_generator/README
|
||||
*/
|
||||
|
||||
#ifndef _BASE_HWCONFIG_FEATURES_H_
|
||||
#define _BASE_HWCONFIG_FEATURES_H_
|
||||
|
||||
enum base_hw_feature {
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_33BIT_VA,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_INTERPIPE_REG_ALIASING,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_MSAA_16X,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_OPTIMIZED_COVERAGE_MASK,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4,
|
||||
BASE_HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE,
|
||||
BASE_HW_FEATURE_BRNDOUT_KILL,
|
||||
BASE_HW_FEATURE_WARPING,
|
||||
BASE_HW_FEATURE_FLUSH_REDUCTION,
|
||||
BASE_HW_FEATURE_V4,
|
||||
BASE_HW_FEATURE_PROTECTED_MODE,
|
||||
#ifdef MALI_INCLUDE_TMIX
|
||||
BASE_HW_FEATURE_COHERENCY_REG,
|
||||
#endif /* MALI_INCLUDE_TMIX */
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_generic[] = {
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t60x[] = {
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_V4,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t62x[] = {
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_V4,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t72x[] = {
|
||||
BASE_HW_FEATURE_33BIT_VA,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_INTERPIPE_REG_ALIASING,
|
||||
BASE_HW_FEATURE_OPTIMIZED_COVERAGE_MASK,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4,
|
||||
BASE_HW_FEATURE_WARPING,
|
||||
BASE_HW_FEATURE_V4,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t76x[] = {
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_MSAA_16X,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_tFxx[] = {
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_BRNDOUT_KILL,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_MSAA_16X,
|
||||
BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t83x[] = {
|
||||
BASE_HW_FEATURE_33BIT_VA,
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_WARPING,
|
||||
BASE_HW_FEATURE_INTERPIPE_REG_ALIASING,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_BRNDOUT_KILL,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_feature base_hw_features_t82x[] = {
|
||||
BASE_HW_FEATURE_33BIT_VA,
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_WARPING,
|
||||
BASE_HW_FEATURE_INTERPIPE_REG_ALIASING,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_BRNDOUT_KILL,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
#if defined(MALI_INCLUDE_TMIX)
|
||||
static const enum base_hw_feature base_hw_features_tMIx[] = {
|
||||
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
|
||||
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
|
||||
BASE_HW_FEATURE_WARPING,
|
||||
BASE_HW_FEATURE_INTERPIPE_REG_ALIASING,
|
||||
BASE_HW_FEATURE_32_BIT_UNIFORM_ADDRESS,
|
||||
BASE_HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL,
|
||||
BASE_HW_FEATURE_BRNDOUT_CC,
|
||||
BASE_HW_FEATURE_BRNDOUT_KILL,
|
||||
BASE_HW_FEATURE_LD_ST_LEA_TEX,
|
||||
BASE_HW_FEATURE_LD_ST_TILEBUFFER,
|
||||
BASE_HW_FEATURE_LINEAR_FILTER_FLOAT,
|
||||
BASE_HW_FEATURE_MRT,
|
||||
BASE_HW_FEATURE_MSAA_16X,
|
||||
BASE_HW_FEATURE_NEXT_INSTRUCTION_TYPE,
|
||||
BASE_HW_FEATURE_OUT_OF_ORDER_EXEC,
|
||||
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
|
||||
BASE_HW_FEATURE_TEST4_DATUM_MODE,
|
||||
BASE_HW_FEATURE_FLUSH_REDUCTION,
|
||||
BASE_HW_FEATURE_PROTECTED_MODE,
|
||||
#ifdef MALI_INCLUDE_TMIX
|
||||
BASE_HW_FEATURE_COHERENCY_REG,
|
||||
#endif /* MALI_INCLUDE_TMIX */
|
||||
BASE_HW_FEATURE_END
|
||||
};
|
||||
|
||||
#endif /* defined(MALI_INCLUDE_TMIX) */
|
||||
|
||||
#endif /* _BASE_HWCONFIG_FEATURES_H_ */
|
||||
775
drivers/gpu/arm/t72x/r7p0/mali_base_hwconfig_issues.h
Normal file
775
drivers/gpu/arm/t72x/r7p0/mali_base_hwconfig_issues.h
Normal file
|
|
@ -0,0 +1,775 @@
|
|||
/*
|
||||
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* AUTOMATICALLY GENERATED FILE. If you want to amend the issues/features,
|
||||
* please update base/tools/hwconfig_generator/hwc_{issues,features}.py
|
||||
* For more information see base/tools/hwconfig_generator/README
|
||||
*/
|
||||
|
||||
#ifndef _BASE_HWCONFIG_ISSUES_H_
|
||||
#define _BASE_HWCONFIG_ISSUES_H_
|
||||
|
||||
enum base_hw_issue {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_6367,
|
||||
BASE_HW_ISSUE_6398,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_6787,
|
||||
BASE_HW_ISSUE_7027,
|
||||
BASE_HW_ISSUE_7144,
|
||||
BASE_HW_ISSUE_7304,
|
||||
BASE_HW_ISSUE_8073,
|
||||
BASE_HW_ISSUE_8186,
|
||||
BASE_HW_ISSUE_8215,
|
||||
BASE_HW_ISSUE_8245,
|
||||
BASE_HW_ISSUE_8250,
|
||||
BASE_HW_ISSUE_8260,
|
||||
BASE_HW_ISSUE_8280,
|
||||
BASE_HW_ISSUE_8316,
|
||||
BASE_HW_ISSUE_8381,
|
||||
BASE_HW_ISSUE_8394,
|
||||
BASE_HW_ISSUE_8401,
|
||||
BASE_HW_ISSUE_8408,
|
||||
BASE_HW_ISSUE_8443,
|
||||
BASE_HW_ISSUE_8456,
|
||||
BASE_HW_ISSUE_8564,
|
||||
BASE_HW_ISSUE_8634,
|
||||
BASE_HW_ISSUE_8778,
|
||||
BASE_HW_ISSUE_8791,
|
||||
BASE_HW_ISSUE_8833,
|
||||
BASE_HW_ISSUE_8879,
|
||||
BASE_HW_ISSUE_8896,
|
||||
BASE_HW_ISSUE_8975,
|
||||
BASE_HW_ISSUE_8986,
|
||||
BASE_HW_ISSUE_8987,
|
||||
BASE_HW_ISSUE_9010,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9418,
|
||||
BASE_HW_ISSUE_9423,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_9510,
|
||||
BASE_HW_ISSUE_9566,
|
||||
BASE_HW_ISSUE_9630,
|
||||
BASE_HW_ISSUE_10127,
|
||||
BASE_HW_ISSUE_10327,
|
||||
BASE_HW_ISSUE_10410,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10487,
|
||||
BASE_HW_ISSUE_10607,
|
||||
BASE_HW_ISSUE_10632,
|
||||
BASE_HW_ISSUE_10676,
|
||||
BASE_HW_ISSUE_10682,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10797,
|
||||
BASE_HW_ISSUE_10817,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10959,
|
||||
BASE_HW_ISSUE_10969,
|
||||
BASE_HW_ISSUE_10984,
|
||||
BASE_HW_ISSUE_10995,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11035,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_generic[] = {
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t60x_r0p0_15dev0[] = {
|
||||
BASE_HW_ISSUE_6367,
|
||||
BASE_HW_ISSUE_6398,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_6787,
|
||||
BASE_HW_ISSUE_7027,
|
||||
BASE_HW_ISSUE_7144,
|
||||
BASE_HW_ISSUE_7304,
|
||||
BASE_HW_ISSUE_8073,
|
||||
BASE_HW_ISSUE_8186,
|
||||
BASE_HW_ISSUE_8215,
|
||||
BASE_HW_ISSUE_8245,
|
||||
BASE_HW_ISSUE_8250,
|
||||
BASE_HW_ISSUE_8260,
|
||||
BASE_HW_ISSUE_8280,
|
||||
BASE_HW_ISSUE_8316,
|
||||
BASE_HW_ISSUE_8381,
|
||||
BASE_HW_ISSUE_8394,
|
||||
BASE_HW_ISSUE_8401,
|
||||
BASE_HW_ISSUE_8408,
|
||||
BASE_HW_ISSUE_8443,
|
||||
BASE_HW_ISSUE_8456,
|
||||
BASE_HW_ISSUE_8564,
|
||||
BASE_HW_ISSUE_8634,
|
||||
BASE_HW_ISSUE_8778,
|
||||
BASE_HW_ISSUE_8791,
|
||||
BASE_HW_ISSUE_8833,
|
||||
BASE_HW_ISSUE_8896,
|
||||
BASE_HW_ISSUE_8975,
|
||||
BASE_HW_ISSUE_8986,
|
||||
BASE_HW_ISSUE_8987,
|
||||
BASE_HW_ISSUE_9010,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9418,
|
||||
BASE_HW_ISSUE_9423,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_9510,
|
||||
BASE_HW_ISSUE_9566,
|
||||
BASE_HW_ISSUE_9630,
|
||||
BASE_HW_ISSUE_10410,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10487,
|
||||
BASE_HW_ISSUE_10607,
|
||||
BASE_HW_ISSUE_10632,
|
||||
BASE_HW_ISSUE_10676,
|
||||
BASE_HW_ISSUE_10682,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10969,
|
||||
BASE_HW_ISSUE_10984,
|
||||
BASE_HW_ISSUE_10995,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11035,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t60x_r0p0_eac[] = {
|
||||
BASE_HW_ISSUE_6367,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_6787,
|
||||
BASE_HW_ISSUE_7027,
|
||||
BASE_HW_ISSUE_7304,
|
||||
BASE_HW_ISSUE_8408,
|
||||
BASE_HW_ISSUE_8564,
|
||||
BASE_HW_ISSUE_8778,
|
||||
BASE_HW_ISSUE_8975,
|
||||
BASE_HW_ISSUE_9010,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9418,
|
||||
BASE_HW_ISSUE_9423,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_9510,
|
||||
BASE_HW_ISSUE_10410,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10487,
|
||||
BASE_HW_ISSUE_10607,
|
||||
BASE_HW_ISSUE_10632,
|
||||
BASE_HW_ISSUE_10676,
|
||||
BASE_HW_ISSUE_10682,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10969,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11035,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t60x_r0p1[] = {
|
||||
BASE_HW_ISSUE_6367,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_6787,
|
||||
BASE_HW_ISSUE_7027,
|
||||
BASE_HW_ISSUE_7304,
|
||||
BASE_HW_ISSUE_8408,
|
||||
BASE_HW_ISSUE_8564,
|
||||
BASE_HW_ISSUE_8778,
|
||||
BASE_HW_ISSUE_8975,
|
||||
BASE_HW_ISSUE_9010,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_9510,
|
||||
BASE_HW_ISSUE_10410,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10487,
|
||||
BASE_HW_ISSUE_10607,
|
||||
BASE_HW_ISSUE_10632,
|
||||
BASE_HW_ISSUE_10676,
|
||||
BASE_HW_ISSUE_10682,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11035,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t62x_r0p1[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10127,
|
||||
BASE_HW_ISSUE_10327,
|
||||
BASE_HW_ISSUE_10410,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10487,
|
||||
BASE_HW_ISSUE_10607,
|
||||
BASE_HW_ISSUE_10632,
|
||||
BASE_HW_ISSUE_10676,
|
||||
BASE_HW_ISSUE_10682,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10817,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10959,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11035,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t62x_r1p0[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10959,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t62x_r1p1[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_10959,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r0p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r0p1[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r0p1_50rel0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r0p2[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r0p3[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_26,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3542,
|
||||
BASE_HW_ISSUE_T76X_3556,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t76x_r1p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t72x_r0p0[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10797,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t72x_r1p0[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10797,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t72x_r1p1[] = {
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10684,
|
||||
BASE_HW_ISSUE_10797,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t72x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10471,
|
||||
BASE_HW_ISSUE_10797,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t76x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t60x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_8778,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t62x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_6402,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10472,
|
||||
BASE_HW_ISSUE_10931,
|
||||
BASE_HW_ISSUE_11012,
|
||||
BASE_HW_ISSUE_11020,
|
||||
BASE_HW_ISSUE_11024,
|
||||
BASE_HW_ISSUE_11042,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_tFRx_r0p1[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_tFRx_r0p2[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_tFRx_r1p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_tFRx_r2p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_tFRx[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t86x_r0p2[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t86x_r1p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t86x_r2p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3966,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t86x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t83x_r0p1[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t83x_r1p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t83x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t82x_r0p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t82x_r0p1[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_t82x_r1p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_10883,
|
||||
BASE_HW_ISSUE_10946,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_T76X_3953,
|
||||
BASE_HW_ISSUE_T76X_3960,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
static const enum base_hw_issue base_hw_issues_model_t82x[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_T76X_1909,
|
||||
BASE_HW_ISSUE_T76X_1963,
|
||||
BASE_HW_ISSUE_T76X_3086,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_T76X_3793,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
#if defined(MALI_INCLUDE_TMIX)
|
||||
static const enum base_hw_issue base_hw_issues_tMIx_r0p0[] = {
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_10821,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
#endif /* defined(MALI_INCLUDE_TMIX) */
|
||||
|
||||
#if defined(MALI_INCLUDE_TMIX)
|
||||
static const enum base_hw_issue base_hw_issues_model_tMIx[] = {
|
||||
BASE_HW_ISSUE_5736,
|
||||
BASE_HW_ISSUE_9275,
|
||||
BASE_HW_ISSUE_9435,
|
||||
BASE_HW_ISSUE_T76X_3700,
|
||||
BASE_HW_ISSUE_END
|
||||
};
|
||||
|
||||
#endif /* defined(MALI_INCLUDE_TMIX) */
|
||||
|
||||
#endif /* _BASE_HWCONFIG_ISSUES_H_ */
|
||||
1679
drivers/gpu/arm/t72x/r7p0/mali_base_kernel.h
Normal file
1679
drivers/gpu/arm/t72x/r7p0/mali_base_kernel.h
Normal file
File diff suppressed because it is too large
Load diff
47
drivers/gpu/arm/t72x/r7p0/mali_base_kernel_sync.h
Normal file
47
drivers/gpu/arm/t72x/r7p0/mali_base_kernel_sync.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 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
|
||||
* Base cross-proccess sync API.
|
||||
*/
|
||||
|
||||
#ifndef _BASE_KERNEL_SYNC_H_
|
||||
#define _BASE_KERNEL_SYNC_H_
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define STREAM_IOC_MAGIC '~'
|
||||
|
||||
/* Fence insert.
|
||||
*
|
||||
* Inserts a fence on the stream operated on.
|
||||
* Fence can be waited via a base fence wait soft-job
|
||||
* or triggered via a base fence trigger soft-job.
|
||||
*
|
||||
* Fences must be cleaned up with close when no longer needed.
|
||||
*
|
||||
* No input/output arguments.
|
||||
* Returns
|
||||
* >=0 fd
|
||||
* <0 error code
|
||||
*/
|
||||
#define STREAM_IOC_FENCE_INSERT _IO(STREAM_IOC_MAGIC, 0)
|
||||
|
||||
#endif /* _BASE_KERNEL_SYNC_H_ */
|
||||
52
drivers/gpu/arm/t72x/r7p0/mali_base_mem_priv.h
Normal file
52
drivers/gpu/arm/t72x/r7p0/mali_base_mem_priv.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _BASE_MEM_PRIV_H_
|
||||
#define _BASE_MEM_PRIV_H_
|
||||
|
||||
#define BASE_SYNCSET_OP_MSYNC (1U << 0)
|
||||
#define BASE_SYNCSET_OP_CSYNC (1U << 1)
|
||||
|
||||
/*
|
||||
* This structure describe a basic memory coherency operation.
|
||||
* It can either be:
|
||||
* @li a sync from CPU to Memory:
|
||||
* - type = ::BASE_SYNCSET_OP_MSYNC
|
||||
* - mem_handle = a handle to the memory object on which the operation
|
||||
* is taking place
|
||||
* - user_addr = the address of the range to be synced
|
||||
* - size = the amount of data to be synced, in bytes
|
||||
* - offset is ignored.
|
||||
* @li a sync from Memory to CPU:
|
||||
* - type = ::BASE_SYNCSET_OP_CSYNC
|
||||
* - mem_handle = a handle to the memory object on which the operation
|
||||
* is taking place
|
||||
* - user_addr = the address of the range to be synced
|
||||
* - size = the amount of data to be synced, in bytes.
|
||||
* - offset is ignored.
|
||||
*/
|
||||
struct basep_syncset {
|
||||
base_mem_handle mem_handle;
|
||||
u64 user_addr;
|
||||
u64 size;
|
||||
u8 type;
|
||||
u8 padding[7];
|
||||
};
|
||||
|
||||
#endif
|
||||
24
drivers/gpu/arm/t72x/r7p0/mali_base_vendor_specific_func.h
Normal file
24
drivers/gpu/arm/t72x/r7p0/mali_base_vendor_specific_func.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010, 2012-2013, 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _BASE_VENDOR_SPEC_FUNC_H_
|
||||
#define _BASE_VENDOR_SPEC_FUNC_H_
|
||||
|
||||
int kbase_get_vendor_specific_cpu_clock_speed(u32 * const);
|
||||
|
||||
#endif /*_BASE_VENDOR_SPEC_FUNC_H_*/
|
||||
585
drivers/gpu/arm/t72x/r7p0/mali_kbase.h
Normal file
585
drivers/gpu/arm/t72x/r7p0/mali_kbase.h
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_H_
|
||||
#define _KBASE_H_
|
||||
|
||||
#include <mali_malisw.h>
|
||||
|
||||
#include <mali_kbase_debug.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "mali_base_kernel.h"
|
||||
#include <mali_kbase_uku.h>
|
||||
#include <mali_kbase_linux.h>
|
||||
|
||||
#include "mali_kbase_pm.h"
|
||||
#include "mali_kbase_mem_lowlevel.h"
|
||||
#include "mali_kbase_defs.h"
|
||||
#include "mali_kbase_trace_timeline.h"
|
||||
#include "mali_kbase_js.h"
|
||||
#include "mali_kbase_mem.h"
|
||||
#include "mali_kbase_security.h"
|
||||
#include "mali_kbase_utility.h"
|
||||
#include "mali_kbase_gpu_memory_debugfs.h"
|
||||
#include "mali_kbase_mem_profile_debugfs.h"
|
||||
#include "mali_kbase_debug_job_fault.h"
|
||||
#include "mali_kbase_jd_debugfs.h"
|
||||
#include "mali_kbase_gpuprops.h"
|
||||
#include "mali_kbase_jm.h"
|
||||
#include "mali_kbase_vinstr.h"
|
||||
#include "mali_kbase_ipa.h"
|
||||
#ifdef CONFIG_GPU_TRACEPOINTS
|
||||
#include <trace/events/gpu.h>
|
||||
#endif
|
||||
|
||||
/*{ SRUK-MALI_SYSTRACE_SUPPORT*/
|
||||
#ifdef CONFIG_MALI_SYSTRACE_SUPPORT
|
||||
/**
|
||||
* @SRUK-android-graphics
|
||||
* Events definition for MALI kernel level systrace stupport
|
||||
* Current implementation only tracks job start/stop events
|
||||
*/
|
||||
|
||||
#define SYSTRACE_EVENT_TYPE_SINGLE 0
|
||||
#define SYSTRACE_EVENT_TYPE_START 1
|
||||
#define SYSTRACE_EVENT_TYPE_STOP 2
|
||||
#define SYSTRACE_EVENT_TYPE_SUSPEND 3
|
||||
#define SYSTRACE_EVENT_TYPE_RESUME 4
|
||||
|
||||
enum {
|
||||
GPU_UNIT_NONE = 0,
|
||||
GPU_UNIT_VP,
|
||||
GPU_UNIT_FP,
|
||||
GPU_UNIT_CL,
|
||||
NUMBER_OF_GPU_UNITS
|
||||
};
|
||||
|
||||
void kbase_systrace_mali_job_slots_event(u8 job_event, u8 job_slot, const struct kbase_context *kctx, u8 atom_id, u64 start_timestamp, u8 dep_0_id, u8 dep_0_type, u8 dep_1_id, u8 dep_1_type, u32 gles_ctx_handle);
|
||||
|
||||
#endif //CONFIG_MALI_SYSTRACE_SUPPORT
|
||||
/* SRUK-MALI_SYSTRACE_SUPPORT }*/
|
||||
|
||||
/**
|
||||
* @page page_base_kernel_main Kernel-side Base (KBase) APIs
|
||||
*
|
||||
* The Kernel-side Base (KBase) APIs are divided up as follows:
|
||||
* - @subpage page_kbase_js_policy
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup base_kbase_api Kernel-side Base (KBase) APIs
|
||||
*/
|
||||
|
||||
struct kbase_device *kbase_device_alloc(void);
|
||||
/*
|
||||
* note: configuration attributes member of kbdev needs to have
|
||||
* been setup before calling kbase_device_init
|
||||
*/
|
||||
|
||||
/*
|
||||
* API to acquire device list semaphone and return pointer
|
||||
* to the device list head
|
||||
*/
|
||||
const struct list_head *kbase_dev_list_get(void);
|
||||
/* API to release the device list semaphore */
|
||||
void kbase_dev_list_put(const struct list_head *dev_list);
|
||||
|
||||
int kbase_device_init(struct kbase_device * const kbdev);
|
||||
void kbase_device_term(struct kbase_device *kbdev);
|
||||
void kbase_device_free(struct kbase_device *kbdev);
|
||||
int kbase_device_has_feature(struct kbase_device *kbdev, u32 feature);
|
||||
|
||||
/* Needed for gator integration and for reporting vsync information */
|
||||
struct kbase_device *kbase_find_device(int minor);
|
||||
void kbase_release_device(struct kbase_device *kbdev);
|
||||
|
||||
void kbase_set_profiling_control(struct kbase_device *kbdev, u32 control, u32 value);
|
||||
|
||||
u32 kbase_get_profiling_control(struct kbase_device *kbdev, u32 control);
|
||||
|
||||
struct kbase_context *
|
||||
kbase_create_context(struct kbase_device *kbdev, bool is_compat);
|
||||
void kbase_destroy_context(struct kbase_context *kctx);
|
||||
int kbase_context_set_create_flags(struct kbase_context *kctx, u32 flags);
|
||||
|
||||
int kbase_jd_init(struct kbase_context *kctx);
|
||||
void kbase_jd_exit(struct kbase_context *kctx);
|
||||
#ifdef BASE_LEGACY_UK6_SUPPORT
|
||||
int kbase_jd_submit(struct kbase_context *kctx,
|
||||
const struct kbase_uk_job_submit *submit_data,
|
||||
int uk6_atom);
|
||||
#else
|
||||
int kbase_jd_submit(struct kbase_context *kctx,
|
||||
const struct kbase_uk_job_submit *submit_data);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kbase_jd_done_worker - Handle a job completion
|
||||
* @data: a &struct work_struct
|
||||
*
|
||||
* This function requeues the job from the runpool (if it was soft-stopped or
|
||||
* removed from NEXT registers).
|
||||
*
|
||||
* Removes it from the system if it finished/failed/was cancelled.
|
||||
*
|
||||
* Resolves dependencies to add dependent jobs to the context, potentially
|
||||
* starting them if necessary (which may add more references to the context)
|
||||
*
|
||||
* Releases the reference to the context from the no-longer-running job.
|
||||
*
|
||||
* Handles retrying submission outside of IRQ context if it failed from within
|
||||
* IRQ context.
|
||||
*/
|
||||
void kbase_jd_done_worker(struct work_struct *data);
|
||||
|
||||
void kbase_jd_done(struct kbase_jd_atom *katom, int slot_nr, ktime_t *end_timestamp,
|
||||
kbasep_js_atom_done_code done_code);
|
||||
void kbase_jd_cancel(struct kbase_device *kbdev, struct kbase_jd_atom *katom);
|
||||
void kbase_jd_evict(struct kbase_device *kbdev, struct kbase_jd_atom *katom);
|
||||
void kbase_jd_zap_context(struct kbase_context *kctx);
|
||||
bool jd_done_nolock(struct kbase_jd_atom *katom,
|
||||
struct list_head *completed_jobs_ctx);
|
||||
void kbase_jd_free_external_resources(struct kbase_jd_atom *katom);
|
||||
bool jd_submit_atom(struct kbase_context *kctx,
|
||||
const struct base_jd_atom_v2 *user_atom,
|
||||
struct kbase_jd_atom *katom);
|
||||
|
||||
void kbase_job_done(struct kbase_device *kbdev, u32 done);
|
||||
|
||||
void kbase_gpu_cacheclean(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom);
|
||||
/**
|
||||
* kbase_job_slot_ctx_priority_check_locked(): - Check for lower priority atoms
|
||||
* and soft stop them
|
||||
* @kctx: Pointer to context to check.
|
||||
* @katom: Pointer to priority atom.
|
||||
*
|
||||
* Atoms from @kctx on the same job slot as @katom, which have lower priority
|
||||
* than @katom will be soft stopped and put back in the queue, so that atoms
|
||||
* with higher priority can run.
|
||||
*
|
||||
* The js_data.runpool_irq.lock must be held when calling this function.
|
||||
*/
|
||||
void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx,
|
||||
struct kbase_jd_atom *katom);
|
||||
|
||||
void kbase_job_slot_softstop(struct kbase_device *kbdev, int js,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
void kbase_job_slot_softstop_swflags(struct kbase_device *kbdev, int js,
|
||||
struct kbase_jd_atom *target_katom, u32 sw_flags);
|
||||
void kbase_job_slot_hardstop(struct kbase_context *kctx, int js,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
void kbase_job_check_enter_disjoint(struct kbase_device *kbdev, u32 action,
|
||||
u16 core_reqs, struct kbase_jd_atom *target_katom);
|
||||
void kbase_job_check_leave_disjoint(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
|
||||
void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *event);
|
||||
int kbase_event_dequeue(struct kbase_context *ctx, struct base_jd_event_v2 *uevent);
|
||||
int kbase_event_pending(struct kbase_context *ctx);
|
||||
int kbase_event_init(struct kbase_context *kctx);
|
||||
void kbase_event_close(struct kbase_context *kctx);
|
||||
void kbase_event_cleanup(struct kbase_context *kctx);
|
||||
void kbase_event_wakeup(struct kbase_context *kctx);
|
||||
|
||||
int kbase_process_soft_job(struct kbase_jd_atom *katom);
|
||||
int kbase_prepare_soft_job(struct kbase_jd_atom *katom);
|
||||
void kbase_finish_soft_job(struct kbase_jd_atom *katom);
|
||||
void kbase_cancel_soft_job(struct kbase_jd_atom *katom);
|
||||
void kbase_resume_suspended_soft_jobs(struct kbase_device *kbdev);
|
||||
|
||||
bool kbase_replay_process(struct kbase_jd_atom *katom);
|
||||
|
||||
/* api used internally for register access. Contains validation and tracing */
|
||||
void kbase_device_trace_register_access(struct kbase_context *kctx, enum kbase_reg_access_type type, u16 reg_offset, u32 reg_value);
|
||||
void kbase_device_trace_buffer_install(struct kbase_context *kctx, u32 *tb, size_t size);
|
||||
void kbase_device_trace_buffer_uninstall(struct kbase_context *kctx);
|
||||
|
||||
/* api to be ported per OS, only need to do the raw register access */
|
||||
void kbase_os_reg_write(struct kbase_device *kbdev, u16 offset, u32 value);
|
||||
u32 kbase_os_reg_read(struct kbase_device *kbdev, u16 offset);
|
||||
|
||||
|
||||
void kbasep_as_do_poke(struct work_struct *work);
|
||||
|
||||
/** Returns the name associated with a Mali exception code
|
||||
*
|
||||
* This function is called from the interrupt handler when a GPU fault occurs.
|
||||
* It reports the details of the fault using KBASE_DEBUG_PRINT_WARN.
|
||||
*
|
||||
* @param[in] kbdev The kbase device that the GPU fault occurred from.
|
||||
* @param[in] exception_code exception code
|
||||
* @return name associated with the exception code
|
||||
*/
|
||||
const char *kbase_exception_name(struct kbase_device *kbdev,
|
||||
u32 exception_code);
|
||||
|
||||
/**
|
||||
* Check whether a system suspend is in progress, or has already been suspended
|
||||
*
|
||||
* The caller should ensure that either kbdev->pm.active_count_lock is held, or
|
||||
* a dmb was executed recently (to ensure the value is most
|
||||
* up-to-date). However, without a lock the value could change afterwards.
|
||||
*
|
||||
* @return false if a suspend is not in progress
|
||||
* @return !=false otherwise
|
||||
*/
|
||||
static inline bool kbase_pm_is_suspending(struct kbase_device *kbdev)
|
||||
{
|
||||
return kbdev->pm.suspending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the atom's ID, as was originally supplied by userspace in
|
||||
* base_jd_atom_v2::atom_number
|
||||
*/
|
||||
static inline int kbase_jd_atom_id(struct kbase_context *kctx, struct kbase_jd_atom *katom)
|
||||
{
|
||||
int result;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kctx);
|
||||
KBASE_DEBUG_ASSERT(katom);
|
||||
KBASE_DEBUG_ASSERT(katom->kctx == kctx);
|
||||
|
||||
result = katom - &kctx->jctx.atoms[0];
|
||||
KBASE_DEBUG_ASSERT(result >= 0 && result <= BASE_JD_ATOM_COUNT);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_jd_atom_from_id - Return the atom structure for the given atom ID
|
||||
* @kctx: Context pointer
|
||||
* @id: ID of atom to retrieve
|
||||
*
|
||||
* Return: Pointer to struct kbase_jd_atom associated with the supplied ID
|
||||
*/
|
||||
static inline struct kbase_jd_atom *kbase_jd_atom_from_id(
|
||||
struct kbase_context *kctx, int id)
|
||||
{
|
||||
return &kctx->jctx.atoms[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the disjoint state
|
||||
*
|
||||
* The disjoint event count and state are both set to zero.
|
||||
*
|
||||
* Disjoint functions usage:
|
||||
*
|
||||
* The disjoint event count should be incremented whenever a disjoint event occurs.
|
||||
*
|
||||
* There are several cases which are regarded as disjoint behavior. Rather than just increment
|
||||
* the counter during disjoint events we also increment the counter when jobs may be affected
|
||||
* by what the GPU is currently doing. To facilitate this we have the concept of disjoint state.
|
||||
*
|
||||
* Disjoint state is entered during GPU reset and for the entire time that an atom is replaying
|
||||
* (as part of the replay workaround). Increasing the disjoint state also increases the count of
|
||||
* disjoint events.
|
||||
*
|
||||
* The disjoint state is then used to increase the count of disjoint events during job submission
|
||||
* and job completion. Any atom submitted or completed while the disjoint state is greater than
|
||||
* zero is regarded as a disjoint event.
|
||||
*
|
||||
* The disjoint event counter is also incremented immediately whenever a job is soft stopped
|
||||
* and during context creation.
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
*/
|
||||
void kbase_disjoint_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Increase the count of disjoint events
|
||||
* called when a disjoint event has happened
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
*/
|
||||
void kbase_disjoint_event(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Increase the count of disjoint events only if the GPU is in a disjoint state
|
||||
*
|
||||
* This should be called when something happens which could be disjoint if the GPU
|
||||
* is in a disjoint state. The state refcount keeps track of this.
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
*/
|
||||
void kbase_disjoint_event_potential(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Returns the count of disjoint events
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
* @return the count of disjoint events
|
||||
*/
|
||||
u32 kbase_disjoint_event_get(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Increment the refcount state indicating that the GPU is in a disjoint state.
|
||||
*
|
||||
* Also Increment the disjoint event count (calls @ref kbase_disjoint_event)
|
||||
* eventually after the disjoint state has completed @ref kbase_disjoint_state_down
|
||||
* should be called
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
*/
|
||||
void kbase_disjoint_state_up(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Decrement the refcount state
|
||||
*
|
||||
* Also Increment the disjoint event count (calls @ref kbase_disjoint_event)
|
||||
*
|
||||
* Called after @ref kbase_disjoint_state_up once the disjoint state is over
|
||||
*
|
||||
* @param kbdev The kbase device
|
||||
*/
|
||||
void kbase_disjoint_state_down(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* If a job is soft stopped and the number of contexts is >= this value
|
||||
* it is reported as a disjoint event
|
||||
*/
|
||||
#define KBASE_DISJOINT_STATE_INTERLEAVED_CONTEXT_COUNT_THRESHOLD 2
|
||||
|
||||
#if KBASE_TRACE_ENABLE
|
||||
void kbasep_trace_debugfs_init(struct kbase_device *kbdev);
|
||||
|
||||
#ifndef CONFIG_MALI_SYSTEM_TRACE
|
||||
/** Add trace values about a job-slot
|
||||
*
|
||||
* @note Any functions called through this macro will still be evaluated in
|
||||
* Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
|
||||
* functions called to get the parameters supplied to this macro must:
|
||||
* - be static or static inline
|
||||
* - must just return 0 and have no other statements present in the body.
|
||||
*/
|
||||
#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, 0)
|
||||
|
||||
/** Add trace values about a job-slot, with info
|
||||
*
|
||||
* @note Any functions called through this macro will still be evaluated in
|
||||
* Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
|
||||
* functions called to get the parameters supplied to this macro must:
|
||||
* - be static or static inline
|
||||
* - must just return 0 and have no other statements present in the body.
|
||||
*/
|
||||
#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
KBASE_TRACE_FLAG_JOBSLOT, 0, jobslot, info_val)
|
||||
|
||||
/** Add trace values about a ctx refcount
|
||||
*
|
||||
* @note Any functions called through this macro will still be evaluated in
|
||||
* Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
|
||||
* functions called to get the parameters supplied to this macro must:
|
||||
* - be static or static inline
|
||||
* - must just return 0 and have no other statements present in the body.
|
||||
*/
|
||||
#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, 0)
|
||||
/** Add trace values about a ctx refcount, and info
|
||||
*
|
||||
* @note Any functions called through this macro will still be evaluated in
|
||||
* Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
|
||||
* functions called to get the parameters supplied to this macro must:
|
||||
* - be static or static inline
|
||||
* - must just return 0 and have no other statements present in the body.
|
||||
*/
|
||||
#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
KBASE_TRACE_FLAG_REFCOUNT, refcount, 0, info_val)
|
||||
|
||||
/** Add trace values (no slot or refcount)
|
||||
*
|
||||
* @note Any functions called through this macro will still be evaluated in
|
||||
* Release builds (CONFIG_MALI_DEBUG not defined). Therefore, when KBASE_TRACE_ENABLE == 0 any
|
||||
* functions called to get the parameters supplied to this macro must:
|
||||
* - be static or static inline
|
||||
* - must just return 0 and have no other statements present in the body.
|
||||
*/
|
||||
#define KBASE_TRACE_ADD(kbdev, code, ctx, katom, gpu_addr, info_val) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
0, 0, 0, info_val)
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define KBASE_TRACE_ADD_EXYNOS(kbdev, code, ctx, katom, gpu_addr, info_val) \
|
||||
kbasep_trace_add(kbdev, KBASE_TRACE_CODE(code), ctx, katom, gpu_addr, \
|
||||
0, 0, 0, info_val)
|
||||
|
||||
/** Clear the trace */
|
||||
#define KBASE_TRACE_CLEAR(kbdev) \
|
||||
kbasep_trace_clear(kbdev)
|
||||
|
||||
/** Dump the slot trace */
|
||||
#define KBASE_TRACE_DUMP(kbdev) \
|
||||
kbasep_trace_dump(kbdev)
|
||||
|
||||
/** PRIVATE - do not use directly. Use KBASE_TRACE_ADD() instead */
|
||||
void kbasep_trace_add(struct kbase_device *kbdev, enum kbase_trace_code code, void *ctx, struct kbase_jd_atom *katom, u64 gpu_addr, u8 flags, int refcount, int jobslot, unsigned long info_val);
|
||||
/** PRIVATE - do not use directly. Use KBASE_TRACE_CLEAR() instead */
|
||||
void kbasep_trace_clear(struct kbase_device *kbdev);
|
||||
#else /* #ifndef CONFIG_MALI_SYSTEM_TRACE */
|
||||
/* Dispatch kbase trace events as system trace events */
|
||||
#include <mali_linux_kbase_trace.h>
|
||||
#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot)\
|
||||
trace_mali_##code(jobslot, 0)
|
||||
|
||||
#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val)\
|
||||
trace_mali_##code(jobslot, info_val)
|
||||
|
||||
#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount)\
|
||||
trace_mali_##code(refcount, 0)
|
||||
|
||||
#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val)\
|
||||
trace_mali_##code(refcount, info_val)
|
||||
|
||||
#define KBASE_TRACE_ADD(kbdev, code, ctx, katom, gpu_addr, info_val)\
|
||||
trace_mali_##code(gpu_addr, info_val)
|
||||
|
||||
#define KBASE_TRACE_CLEAR(kbdev)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
#define KBASE_TRACE_DUMP(kbdev)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
#endif /* #ifndef CONFIG_MALI_SYSTEM_TRACE */
|
||||
#else
|
||||
#define KBASE_TRACE_ADD_SLOT(kbdev, code, ctx, katom, gpu_addr, jobslot)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(gpu_addr);\
|
||||
CSTD_UNUSED(jobslot);\
|
||||
} while (0)
|
||||
|
||||
#define KBASE_TRACE_ADD_SLOT_INFO(kbdev, code, ctx, katom, gpu_addr, jobslot, info_val)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(gpu_addr);\
|
||||
CSTD_UNUSED(jobslot);\
|
||||
CSTD_UNUSED(info_val);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
#define KBASE_TRACE_ADD_REFCOUNT(kbdev, code, ctx, katom, gpu_addr, refcount)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(gpu_addr);\
|
||||
CSTD_UNUSED(refcount);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
#define KBASE_TRACE_ADD_REFCOUNT_INFO(kbdev, code, ctx, katom, gpu_addr, refcount, info_val)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(gpu_addr);\
|
||||
CSTD_UNUSED(info_val);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
#define KBASE_TRACE_ADD(kbdev, code, subcode, ctx, katom, val)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(subcode);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(val);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define KBASE_TRACE_ADD_EXYNOS(kbdev, code, subcode, ctx, katom, val)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(code);\
|
||||
CSTD_UNUSED(subcode);\
|
||||
CSTD_UNUSED(ctx);\
|
||||
CSTD_UNUSED(katom);\
|
||||
CSTD_UNUSED(val);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
|
||||
#define KBASE_TRACE_CLEAR(kbdev)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
#define KBASE_TRACE_DUMP(kbdev)\
|
||||
do {\
|
||||
CSTD_UNUSED(kbdev);\
|
||||
CSTD_NOP(0);\
|
||||
} while (0)
|
||||
#endif /* KBASE_TRACE_ENABLE */
|
||||
/** PRIVATE - do not use directly. Use KBASE_TRACE_DUMP() instead */
|
||||
void kbasep_trace_dump(struct kbase_device *kbdev);
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
/**
|
||||
* kbase_set_driver_inactive - Force driver to go inactive
|
||||
* @kbdev: Device pointer
|
||||
* @inactive: true if driver should go inactive, false otherwise
|
||||
*
|
||||
* Forcing the driver inactive will cause all future IOCTLs to wait until the
|
||||
* driver is made active again. This is intended solely for the use of tests
|
||||
* which require that no jobs are running while the test executes.
|
||||
*/
|
||||
void kbase_set_driver_inactive(struct kbase_device *kbdev, bool inactive);
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
void gpu_dump_register_hooks(struct kbase_device *kbdev);
|
||||
|
||||
#endif
|
||||
209
drivers/gpu/arm/t72x/r7p0/mali_kbase_10969_workaround.c
Normal file
209
drivers/gpu/arm/t72x/r7p0/mali_kbase_10969_workaround.c
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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/dma-mapping.h>
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_10969_workaround.h>
|
||||
|
||||
/* This function is used to solve an HW issue with single iterator GPUs.
|
||||
* If a fragment job is soft-stopped on the edge of its bounding box, can happen that the
|
||||
* restart index is out of bounds and the rerun causes a tile range fault. If this happens
|
||||
* we try to clamp the restart index to a correct value and rerun the job.
|
||||
*/
|
||||
/* Mask of X and Y coordinates for the coordinates words in the descriptors*/
|
||||
#define X_COORDINATE_MASK 0x00000FFF
|
||||
#define Y_COORDINATE_MASK 0x0FFF0000
|
||||
/* Max number of words needed from the fragment shader job descriptor */
|
||||
#define JOB_HEADER_SIZE_IN_WORDS 10
|
||||
#define JOB_HEADER_SIZE (JOB_HEADER_SIZE_IN_WORDS*sizeof(u32))
|
||||
|
||||
/* Word 0: Status Word */
|
||||
#define JOB_DESC_STATUS_WORD 0
|
||||
/* Word 1: Restart Index */
|
||||
#define JOB_DESC_RESTART_INDEX_WORD 1
|
||||
/* Word 2: Fault address low word */
|
||||
#define JOB_DESC_FAULT_ADDR_LOW_WORD 2
|
||||
/* Word 8: Minimum Tile Coordinates */
|
||||
#define FRAG_JOB_DESC_MIN_TILE_COORD_WORD 8
|
||||
/* Word 9: Maximum Tile Coordinates */
|
||||
#define FRAG_JOB_DESC_MAX_TILE_COORD_WORD 9
|
||||
|
||||
int kbasep_10969_workaround_clamp_coordinates(struct kbase_jd_atom *katom)
|
||||
{
|
||||
struct device *dev = katom->kctx->kbdev->dev;
|
||||
u32 clamped = 0;
|
||||
struct kbase_va_region *region;
|
||||
phys_addr_t *page_array;
|
||||
u64 page_index;
|
||||
u32 offset = katom->jc & (~PAGE_MASK);
|
||||
u32 *page_1 = NULL;
|
||||
u32 *page_2 = NULL;
|
||||
u32 job_header[JOB_HEADER_SIZE_IN_WORDS];
|
||||
void *dst = job_header;
|
||||
u32 minX, minY, maxX, maxY;
|
||||
u32 restartX, restartY;
|
||||
struct page *p;
|
||||
u32 copy_size;
|
||||
|
||||
dev_warn(dev, "Called TILE_RANGE_FAULT workaround clamping function.\n");
|
||||
if (!(katom->core_req & BASE_JD_REQ_FS))
|
||||
return 0;
|
||||
|
||||
kbase_gpu_vm_lock(katom->kctx);
|
||||
region = kbase_region_tracker_find_region_enclosing_address(katom->kctx,
|
||||
katom->jc);
|
||||
if (!region || (region->flags & KBASE_REG_FREE))
|
||||
goto out_unlock;
|
||||
|
||||
page_array = kbase_get_cpu_phy_pages(region);
|
||||
if (!page_array)
|
||||
goto out_unlock;
|
||||
|
||||
page_index = (katom->jc >> PAGE_SHIFT) - region->start_pfn;
|
||||
|
||||
p = pfn_to_page(PFN_DOWN(page_array[page_index]));
|
||||
|
||||
/* we need the first 10 words of the fragment shader job descriptor.
|
||||
* We need to check that the offset + 10 words is less that the page
|
||||
* size otherwise we need to load the next page.
|
||||
* page_size_overflow will be equal to 0 in case the whole descriptor
|
||||
* is within the page > 0 otherwise.
|
||||
*/
|
||||
copy_size = MIN(PAGE_SIZE - offset, JOB_HEADER_SIZE);
|
||||
|
||||
page_1 = kmap_atomic(p);
|
||||
|
||||
/* page_1 is a u32 pointer, offset is expressed in bytes */
|
||||
page_1 += offset>>2;
|
||||
|
||||
kbase_sync_single_for_cpu(katom->kctx->kbdev,
|
||||
kbase_dma_addr(p) + offset,
|
||||
copy_size, DMA_BIDIRECTIONAL);
|
||||
|
||||
memcpy(dst, page_1, copy_size);
|
||||
|
||||
/* The data needed overflows page the dimension,
|
||||
* need to map the subsequent page */
|
||||
if (copy_size < JOB_HEADER_SIZE) {
|
||||
p = pfn_to_page(PFN_DOWN(page_array[page_index + 1]));
|
||||
page_2 = kmap_atomic(p);
|
||||
|
||||
kbase_sync_single_for_cpu(katom->kctx->kbdev,
|
||||
kbase_dma_addr(p),
|
||||
JOB_HEADER_SIZE - copy_size, DMA_BIDIRECTIONAL);
|
||||
|
||||
memcpy(dst + copy_size, page_2, JOB_HEADER_SIZE - copy_size);
|
||||
}
|
||||
|
||||
/* We managed to correctly map one or two pages (in case of overflow) */
|
||||
/* Get Bounding Box data and restart index from fault address low word */
|
||||
minX = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & X_COORDINATE_MASK;
|
||||
minY = job_header[FRAG_JOB_DESC_MIN_TILE_COORD_WORD] & Y_COORDINATE_MASK;
|
||||
maxX = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & X_COORDINATE_MASK;
|
||||
maxY = job_header[FRAG_JOB_DESC_MAX_TILE_COORD_WORD] & Y_COORDINATE_MASK;
|
||||
restartX = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & X_COORDINATE_MASK;
|
||||
restartY = job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] & Y_COORDINATE_MASK;
|
||||
|
||||
dev_warn(dev, "Before Clamping:\n"
|
||||
"Jobstatus: %08x\n"
|
||||
"restartIdx: %08x\n"
|
||||
"Fault_addr_low: %08x\n"
|
||||
"minCoordsX: %08x minCoordsY: %08x\n"
|
||||
"maxCoordsX: %08x maxCoordsY: %08x\n",
|
||||
job_header[JOB_DESC_STATUS_WORD],
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD],
|
||||
job_header[JOB_DESC_FAULT_ADDR_LOW_WORD],
|
||||
minX, minY,
|
||||
maxX, maxY);
|
||||
|
||||
/* Set the restart index to the one which generated the fault*/
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD] =
|
||||
job_header[JOB_DESC_FAULT_ADDR_LOW_WORD];
|
||||
|
||||
if (restartX < minX) {
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD] = (minX) | restartY;
|
||||
dev_warn(dev,
|
||||
"Clamping restart X index to minimum. %08x clamped to %08x\n",
|
||||
restartX, minX);
|
||||
clamped = 1;
|
||||
}
|
||||
if (restartY < minY) {
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD] = (minY) | restartX;
|
||||
dev_warn(dev,
|
||||
"Clamping restart Y index to minimum. %08x clamped to %08x\n",
|
||||
restartY, minY);
|
||||
clamped = 1;
|
||||
}
|
||||
if (restartX > maxX) {
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxX) | restartY;
|
||||
dev_warn(dev,
|
||||
"Clamping restart X index to maximum. %08x clamped to %08x\n",
|
||||
restartX, maxX);
|
||||
clamped = 1;
|
||||
}
|
||||
if (restartY > maxY) {
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD] = (maxY) | restartX;
|
||||
dev_warn(dev,
|
||||
"Clamping restart Y index to maximum. %08x clamped to %08x\n",
|
||||
restartY, maxY);
|
||||
clamped = 1;
|
||||
}
|
||||
|
||||
if (clamped) {
|
||||
/* Reset the fault address low word
|
||||
* and set the job status to STOPPED */
|
||||
job_header[JOB_DESC_FAULT_ADDR_LOW_WORD] = 0x0;
|
||||
job_header[JOB_DESC_STATUS_WORD] = BASE_JD_EVENT_STOPPED;
|
||||
dev_warn(dev, "After Clamping:\n"
|
||||
"Jobstatus: %08x\n"
|
||||
"restartIdx: %08x\n"
|
||||
"Fault_addr_low: %08x\n"
|
||||
"minCoordsX: %08x minCoordsY: %08x\n"
|
||||
"maxCoordsX: %08x maxCoordsY: %08x\n",
|
||||
job_header[JOB_DESC_STATUS_WORD],
|
||||
job_header[JOB_DESC_RESTART_INDEX_WORD],
|
||||
job_header[JOB_DESC_FAULT_ADDR_LOW_WORD],
|
||||
minX, minY,
|
||||
maxX, maxY);
|
||||
|
||||
/* Flush CPU cache to update memory for future GPU reads*/
|
||||
memcpy(page_1, dst, copy_size);
|
||||
p = pfn_to_page(PFN_DOWN(page_array[page_index]));
|
||||
|
||||
kbase_sync_single_for_device(katom->kctx->kbdev,
|
||||
kbase_dma_addr(p) + offset,
|
||||
copy_size, DMA_TO_DEVICE);
|
||||
|
||||
if (copy_size < JOB_HEADER_SIZE) {
|
||||
memcpy(page_2, dst + copy_size,
|
||||
JOB_HEADER_SIZE - copy_size);
|
||||
p = pfn_to_page(PFN_DOWN(page_array[page_index + 1]));
|
||||
|
||||
kbase_sync_single_for_device(katom->kctx->kbdev,
|
||||
kbase_dma_addr(p),
|
||||
JOB_HEADER_SIZE - copy_size,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
}
|
||||
if (copy_size < JOB_HEADER_SIZE)
|
||||
kunmap_atomic(page_2);
|
||||
|
||||
kunmap_atomic(page_1);
|
||||
|
||||
out_unlock:
|
||||
kbase_gpu_vm_unlock(katom->kctx);
|
||||
return clamped;
|
||||
}
|
||||
23
drivers/gpu/arm/t72x/r7p0/mali_kbase_10969_workaround.h
Normal file
23
drivers/gpu/arm/t72x/r7p0/mali_kbase_10969_workaround.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_10969_WORKAROUND_
|
||||
#define _KBASE_10969_WORKAROUND_
|
||||
|
||||
int kbasep_10969_workaround_clamp_coordinates(struct kbase_jd_atom *katom);
|
||||
|
||||
#endif /* _KBASE_10969_WORKAROUND_ */
|
||||
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_cache_policy.c
Normal file
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_cache_policy.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Cache Policy API.
|
||||
*/
|
||||
|
||||
#include "mali_kbase_cache_policy.h"
|
||||
|
||||
/*
|
||||
* The output flags should be a combination of the following values:
|
||||
* KBASE_REG_CPU_CACHED: CPU cache should be enabled.
|
||||
*/
|
||||
u32 kbase_cache_enabled(u32 flags, u32 nr_pages)
|
||||
{
|
||||
u32 cache_flags = 0;
|
||||
|
||||
CSTD_UNUSED(nr_pages);
|
||||
|
||||
if (flags & BASE_MEM_CACHED_CPU)
|
||||
cache_flags |= KBASE_REG_CPU_CACHED;
|
||||
|
||||
return cache_flags;
|
||||
}
|
||||
|
||||
|
||||
void kbase_sync_single_for_device(struct kbase_device *kbdev, dma_addr_t handle,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_for_device(kbdev->dev, handle, size, dir);
|
||||
}
|
||||
|
||||
|
||||
void kbase_sync_single_for_cpu(struct kbase_device *kbdev, dma_addr_t handle,
|
||||
size_t size, enum dma_data_direction dir)
|
||||
{
|
||||
dma_sync_single_for_cpu(kbdev->dev, handle, size, dir);
|
||||
}
|
||||
45
drivers/gpu/arm/t72x/r7p0/mali_kbase_cache_policy.h
Normal file
45
drivers/gpu/arm/t72x/r7p0/mali_kbase_cache_policy.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2013, 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Cache Policy API.
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_CACHE_POLICY_H_
|
||||
#define _KBASE_CACHE_POLICY_H_
|
||||
|
||||
#include "mali_kbase.h"
|
||||
#include "mali_base_kernel.h"
|
||||
|
||||
/**
|
||||
* kbase_cache_enabled - Choose the cache policy for a specific region
|
||||
* @flags: flags describing attributes of the region
|
||||
* @nr_pages: total number of pages (backed or not) for the region
|
||||
*
|
||||
* Tells whether the CPU and GPU caches should be enabled or not for a specific
|
||||
* region.
|
||||
* This function can be modified to customize the cache policy depending on the
|
||||
* flags and size of the region.
|
||||
*
|
||||
* Return: a combination of %KBASE_REG_CPU_CACHED and %KBASE_REG_GPU_CACHED
|
||||
* depending on the cache policy
|
||||
*/
|
||||
u32 kbase_cache_enabled(u32 flags, u32 nr_pages);
|
||||
|
||||
#endif /* _KBASE_CACHE_POLICY_H_ */
|
||||
51
drivers/gpu/arm/t72x/r7p0/mali_kbase_config.c
Normal file
51
drivers/gpu/arm/t72x/r7p0/mali_kbase_config.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <mali_kbase_defs.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
|
||||
int kbasep_platform_device_init(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_platform_funcs_conf *platform_funcs_p;
|
||||
|
||||
platform_funcs_p = (struct kbase_platform_funcs_conf *)PLATFORM_FUNCS;
|
||||
if (platform_funcs_p && platform_funcs_p->platform_init_func)
|
||||
return platform_funcs_p->platform_init_func(kbdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kbasep_platform_device_term(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_platform_funcs_conf *platform_funcs_p;
|
||||
|
||||
platform_funcs_p = (struct kbase_platform_funcs_conf *)PLATFORM_FUNCS;
|
||||
if (platform_funcs_p && platform_funcs_p->platform_term_func)
|
||||
platform_funcs_p->platform_term_func(kbdev);
|
||||
}
|
||||
|
||||
int kbase_cpuprops_get_default_clock_speed(u32 * const clock_speed)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(NULL != clock_speed);
|
||||
|
||||
*clock_speed = 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
337
drivers/gpu/arm/t72x/r7p0/mali_kbase_config.h
Normal file
337
drivers/gpu/arm/t72x/r7p0/mali_kbase_config.h
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_config.h
|
||||
* Configuration API and Attributes for KBase
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_CONFIG_H_
|
||||
#define _KBASE_CONFIG_H_
|
||||
|
||||
#include <asm/page.h>
|
||||
|
||||
#include <mali_malisw.h>
|
||||
#include <mali_kbase_backend_config.h>
|
||||
|
||||
/**
|
||||
* @addtogroup base_api
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup base_kbase_api
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup kbase_config Configuration API and Attributes
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if !MALI_CUSTOMER_RELEASE
|
||||
/* This flag is set for internal builds so we can run tests without credentials. */
|
||||
#define KBASE_HWCNT_DUMP_BYPASS_ROOT 1
|
||||
#else
|
||||
#define KBASE_HWCNT_DUMP_BYPASS_ROOT 0
|
||||
#endif
|
||||
|
||||
#include <linux/rbtree.h>
|
||||
|
||||
/* Forward declaration of struct kbase_device */
|
||||
struct kbase_device;
|
||||
|
||||
/**
|
||||
* kbase_platform_funcs_conf - Specifies platform init/term function pointers
|
||||
*
|
||||
* Specifies the functions pointers for platform specific initialization and
|
||||
* termination. By default no functions are required. No additional platform
|
||||
* specific control is necessary.
|
||||
*/
|
||||
struct kbase_platform_funcs_conf {
|
||||
/**
|
||||
* platform_init_func - platform specific init function pointer
|
||||
* @kbdev - kbase_device pointer
|
||||
*
|
||||
* Returns 0 on success, negative error code otherwise.
|
||||
*
|
||||
* Function pointer for platform specific initialization or NULL if no
|
||||
* initialization function is required. At the point this the GPU is
|
||||
* not active and its power and clocks are in unknown (platform specific
|
||||
* state) as kbase doesn't yet have control of power and clocks.
|
||||
*
|
||||
* The platform specific private pointer kbase_device::platform_context
|
||||
* can be accessed (and possibly initialized) in here.
|
||||
*/
|
||||
int (*platform_init_func)(struct kbase_device *kbdev);
|
||||
/**
|
||||
* platform_term_func - platform specific termination function pointer
|
||||
* @kbdev - kbase_device pointer
|
||||
*
|
||||
* Function pointer for platform specific termination or NULL if no
|
||||
* termination function is required. At the point this the GPU will be
|
||||
* idle but still powered and clocked.
|
||||
*
|
||||
* The platform specific private pointer kbase_device::platform_context
|
||||
* can be accessed (and possibly terminated) in here.
|
||||
*/
|
||||
void (*platform_term_func)(struct kbase_device *kbdev);
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Specifies the callbacks for power management
|
||||
*
|
||||
* By default no callbacks will be made and the GPU must not be powered off.
|
||||
*/
|
||||
struct kbase_pm_callback_conf {
|
||||
/** Callback for when the GPU is idle and the power to it can be switched off.
|
||||
*
|
||||
* The system integrator can decide whether to either do nothing, just switch off
|
||||
* the clocks to the GPU, or to completely power down the GPU.
|
||||
* The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the
|
||||
* platform \em callbacks responsiblity to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf).
|
||||
*/
|
||||
void (*power_off_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for when the GPU is about to become active and power must be supplied.
|
||||
*
|
||||
* This function must not return until the GPU is powered and clocked sufficiently for register access to
|
||||
* succeed. The return value specifies whether the GPU was powered down since the call to power_off_callback.
|
||||
* If the GPU state has been lost then this function must return 1, otherwise it should return 0.
|
||||
* The platform specific private pointer kbase_device::platform_context can be accessed and modified in here. It is the
|
||||
* platform \em callbacks responsiblity to initialize and terminate this pointer if used (see @ref kbase_platform_funcs_conf).
|
||||
*
|
||||
* The return value of the first call to this function is ignored.
|
||||
*
|
||||
* @return 1 if the GPU state may have been lost, 0 otherwise.
|
||||
*/
|
||||
int (*power_on_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for when the system is requesting a suspend and GPU power
|
||||
* must be switched off.
|
||||
*
|
||||
* Note that if this callback is present, then this may be called
|
||||
* without a preceding call to power_off_callback. Therefore this
|
||||
* callback must be able to take any action that might otherwise happen
|
||||
* in power_off_callback.
|
||||
*
|
||||
* The platform specific private pointer kbase_device::platform_context
|
||||
* can be accessed and modified in here. It is the platform \em
|
||||
* callbacks responsibility to initialize and terminate this pointer if
|
||||
* used (see @ref kbase_platform_funcs_conf).
|
||||
*/
|
||||
void (*power_suspend_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for when the system is resuming from a suspend and GPU
|
||||
* power must be switched on.
|
||||
*
|
||||
* Note that if this callback is present, then this may be called
|
||||
* without a following call to power_on_callback. Therefore this
|
||||
* callback must be able to take any action that might otherwise happen
|
||||
* in power_on_callback.
|
||||
*
|
||||
* The platform specific private pointer kbase_device::platform_context
|
||||
* can be accessed and modified in here. It is the platform \em
|
||||
* callbacks responsibility to initialize and terminate this pointer if
|
||||
* used (see @ref kbase_platform_funcs_conf).
|
||||
*/
|
||||
void (*power_resume_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for handling runtime power management initialization.
|
||||
*
|
||||
* The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback
|
||||
* will become active from calls made to the OS from within this function.
|
||||
* The runtime calls can be triggered by calls from @ref power_off_callback and @ref power_on_callback.
|
||||
* Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
|
||||
*
|
||||
* @return 0 on success, else int erro code.
|
||||
*/
|
||||
int (*power_runtime_init_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for handling runtime power management termination.
|
||||
*
|
||||
* The runtime power management callbacks @ref power_runtime_off_callback and @ref power_runtime_on_callback
|
||||
* should no longer be called by the OS on completion of this function.
|
||||
* Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
|
||||
*/
|
||||
void (*power_runtime_term_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for runtime power-off power management callback
|
||||
*
|
||||
* For linux this callback will be called by the kernel runtime_suspend callback.
|
||||
* Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
|
||||
*
|
||||
* @return 0 on success, else OS error code.
|
||||
*/
|
||||
void (*power_runtime_off_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/** Callback for runtime power-on power management callback
|
||||
*
|
||||
* For linux this callback will be called by the kernel runtime_resume callback.
|
||||
* Note: for linux the kernel must have CONFIG_PM_RUNTIME enabled to use this feature.
|
||||
*/
|
||||
int (*power_runtime_on_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
/** Callback for GPU DVFS handler start/stop
|
||||
**/
|
||||
int (*power_dvfs_on_callback)(struct kbase_device *kbdev);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
/** Callback for change DVFS level as fixed clock
|
||||
**/
|
||||
int (*power_change_dvfs_level_callback)(struct kbase_device *kbdev);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* kbase_cpuprops_get_default_clock_speed - default for CPU_SPEED_FUNC
|
||||
* @clock_speed - see kbase_cpu_clk_speed_func for details on the parameters
|
||||
*
|
||||
* Returns 0 on success, negative error code otherwise.
|
||||
*
|
||||
* Default implementation of CPU_SPEED_FUNC. This function sets clock_speed
|
||||
* to 100, so will be an underestimate for any real system.
|
||||
*/
|
||||
int kbase_cpuprops_get_default_clock_speed(u32 * const clock_speed);
|
||||
|
||||
/**
|
||||
* kbase_cpu_clk_speed_func - Type of the function pointer for CPU_SPEED_FUNC
|
||||
* @param clock_speed - pointer to store the current CPU clock speed in MHz
|
||||
*
|
||||
* Returns 0 on success, otherwise negative error code.
|
||||
*
|
||||
* This is mainly used to implement OpenCL's clGetDeviceInfo().
|
||||
*/
|
||||
typedef int (*kbase_cpu_clk_speed_func) (u32 *clock_speed);
|
||||
|
||||
/**
|
||||
* kbase_gpu_clk_speed_func - Type of the function pointer for GPU_SPEED_FUNC
|
||||
* @param clock_speed - pointer to store the current GPU clock speed in MHz
|
||||
*
|
||||
* Returns 0 on success, otherwise negative error code.
|
||||
* When an error is returned the caller assumes maximum GPU speed stored in
|
||||
* gpu_freq_khz_max.
|
||||
*
|
||||
* If the system timer is not available then this function is required
|
||||
* for the OpenCL queue profiling to return correct timing information.
|
||||
*
|
||||
*/
|
||||
typedef int (*kbase_gpu_clk_speed_func) (u32 *clock_speed);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct kbase_platform_config {
|
||||
};
|
||||
#else
|
||||
|
||||
/*
|
||||
* @brief Specifies start and end of I/O memory region.
|
||||
*/
|
||||
struct kbase_io_memory_region {
|
||||
u64 start;
|
||||
u64 end;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Specifies I/O related resources like IRQs and memory region for I/O operations.
|
||||
*/
|
||||
struct kbase_io_resources {
|
||||
u32 job_irq_number;
|
||||
u32 mmu_irq_number;
|
||||
u32 gpu_irq_number;
|
||||
struct kbase_io_memory_region io_memory_region;
|
||||
};
|
||||
|
||||
struct kbase_platform_config {
|
||||
const struct kbase_io_resources *io_resources;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
* @brief Gets the pointer to platform config.
|
||||
*
|
||||
* @return Pointer to the platform config
|
||||
*/
|
||||
struct kbase_platform_config *kbase_get_platform_config(void);
|
||||
|
||||
/**
|
||||
* kbasep_platform_device_init: - Platform specific call to initialize hardware
|
||||
* @kbdev: kbase device pointer
|
||||
*
|
||||
* Function calls a platform defined routine if specified in the configuration
|
||||
* attributes. The routine can initialize any hardware and context state that
|
||||
* is required for the GPU block to function.
|
||||
*
|
||||
* Return: 0 if no errors have been found in the config.
|
||||
* Negative error code otherwise.
|
||||
*/
|
||||
int kbasep_platform_device_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbasep_platform_device_term - Platform specific call to terminate hardware
|
||||
* @kbdev: Kbase device pointer
|
||||
*
|
||||
* Function calls a platform defined routine if specified in the configuration
|
||||
* attributes. The routine can destroy any platform specific context state and
|
||||
* shut down any hardware functionality that are outside of the Power Management
|
||||
* callbacks.
|
||||
*
|
||||
*/
|
||||
void kbasep_platform_device_term(struct kbase_device *kbdev);
|
||||
|
||||
|
||||
/**
|
||||
* kbase_platform_early_init - Early initialisation of the platform code
|
||||
*
|
||||
* This function will be called when the module is loaded to perform any
|
||||
* early initialisation required by the platform code. Such as reading
|
||||
* platform specific device tree entries for the GPU.
|
||||
*
|
||||
* Return: 0 for success, any other fail causes module initialisation to fail
|
||||
*/
|
||||
int kbase_platform_early_init(void);
|
||||
|
||||
#ifndef CONFIG_OF
|
||||
#ifdef CONFIG_MALI_PLATFORM_FAKE
|
||||
/**
|
||||
* kbase_platform_fake_register - Register a platform device for the GPU
|
||||
*
|
||||
* This can be used to register a platform device on systems where device tree
|
||||
* is not enabled and the platform initialisation code in the kernel doesn't
|
||||
* create the GPU device. Where possible device tree should be used instead.
|
||||
*
|
||||
* Return: 0 for success, any other fail causes module initialisation to fail
|
||||
*/
|
||||
int kbase_platform_fake_register(void);
|
||||
|
||||
/**
|
||||
* kbase_platform_fake_unregister - Unregister a fake platform device
|
||||
*
|
||||
* Unregister the platform device created with kbase_platform_fake_register()
|
||||
*/
|
||||
void kbase_platform_fake_unregister(void);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** @} *//* end group kbase_config */
|
||||
/** @} *//* end group base_kbase_api */
|
||||
/** @} *//* end group base_api */
|
||||
|
||||
#endif /* _KBASE_CONFIG_H_ */
|
||||
263
drivers/gpu/arm/t72x/r7p0/mali_kbase_config_defaults.h
Normal file
263
drivers/gpu/arm/t72x/r7p0/mali_kbase_config_defaults.h
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_config_defaults.h
|
||||
*
|
||||
* Default values for configuration settings
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_CONFIG_DEFAULTS_H_
|
||||
#define _KBASE_CONFIG_DEFAULTS_H_
|
||||
|
||||
/* Include mandatory definitions per platform */
|
||||
#include <mali_kbase_config_platform.h>
|
||||
|
||||
/**
|
||||
* Irq throttle. It is the minimum desired time in between two
|
||||
* consecutive gpu interrupts (given in 'us'). The irq throttle
|
||||
* gpu register will be configured after this, taking into
|
||||
* account the configured max frequency.
|
||||
*
|
||||
* Attached value: number in micro seconds
|
||||
*/
|
||||
#define DEFAULT_IRQ_THROTTLE_TIME_US 20
|
||||
|
||||
/**
|
||||
* Default Job Scheduler initial runtime of a context for the CFS Policy,
|
||||
* in time-slices.
|
||||
*
|
||||
* This value is relative to that of the least-run context, and defines
|
||||
* where in the CFS queue a new context is added. A value of 1 means 'after
|
||||
* the least-run context has used its timeslice'. Therefore, when all
|
||||
* contexts consistently use the same amount of time, a value of 1 models a
|
||||
* FIFO. A value of 0 would model a LIFO.
|
||||
*
|
||||
* The value is represented in "numbers of time slices". Multiply this
|
||||
* value by that defined in @ref DEFAULT_JS_CTX_TIMESLICE_NS to get
|
||||
* the time value for this in nanoseconds.
|
||||
*/
|
||||
#define DEFAULT_JS_CFS_CTX_RUNTIME_INIT_SLICES 1
|
||||
|
||||
/**
|
||||
* Default Job Scheduler minimum runtime value of a context for CFS, in
|
||||
* time_slices relative to that of the least-run context.
|
||||
*
|
||||
* This is a measure of how much preferrential treatment is given to a
|
||||
* context that is not run very often.
|
||||
*
|
||||
* Specficially, this value defines how many timeslices such a context is
|
||||
* (initially) allowed to use at once. Such contexts (e.g. 'interactive'
|
||||
* processes) will appear near the front of the CFS queue, and can initially
|
||||
* use more time than contexts that run continuously (e.g. 'batch'
|
||||
* processes).
|
||||
*
|
||||
* This limit \b prevents a "stored-up timeslices" DoS attack, where a ctx
|
||||
* not run for a long time attacks the system by using a very large initial
|
||||
* number of timeslices when it finally does run.
|
||||
*
|
||||
* @note A value of zero allows not-run-often contexts to get scheduled in
|
||||
* quickly, but to only use a single timeslice when they get scheduled in.
|
||||
*/
|
||||
#define DEFAULT_JS_CFS_CTX_RUNTIME_MIN_SLICES 2
|
||||
|
||||
/**
|
||||
* Boolean indicating whether the driver is configured to be secure at
|
||||
* a potential loss of performance.
|
||||
*
|
||||
* This currently affects only r0p0-15dev0 HW and earlier.
|
||||
*
|
||||
* On r0p0-15dev0 HW and earlier, there are tradeoffs between security and
|
||||
* performance:
|
||||
*
|
||||
* - When this is set to true, the driver remains fully secure,
|
||||
* but potentially loses performance compared with setting this to
|
||||
* false.
|
||||
* - When set to false, the driver is open to certain security
|
||||
* attacks.
|
||||
*
|
||||
* From r0p0-00rel0 and onwards, there is no security loss by setting
|
||||
* this to false, and no performance loss by setting it to
|
||||
* true.
|
||||
*/
|
||||
#define DEFAULT_SECURE_BUT_LOSS_OF_PERFORMANCE false
|
||||
|
||||
enum {
|
||||
/**
|
||||
* Use unrestricted Address ID width on the AXI bus.
|
||||
*/
|
||||
KBASE_AID_32 = 0x0,
|
||||
|
||||
/**
|
||||
* Restrict GPU to a half of maximum Address ID count.
|
||||
* This will reduce performance, but reduce bus load due to GPU.
|
||||
*/
|
||||
KBASE_AID_16 = 0x3,
|
||||
|
||||
/**
|
||||
* Restrict GPU to a quarter of maximum Address ID count.
|
||||
* This will reduce performance, but reduce bus load due to GPU.
|
||||
*/
|
||||
KBASE_AID_8 = 0x2,
|
||||
|
||||
/**
|
||||
* Restrict GPU to an eighth of maximum Address ID count.
|
||||
* This will reduce performance, but reduce bus load due to GPU.
|
||||
*/
|
||||
KBASE_AID_4 = 0x1
|
||||
};
|
||||
|
||||
/**
|
||||
* Default setting for read Address ID limiting on AXI bus.
|
||||
*
|
||||
* Attached value: u32 register value
|
||||
* KBASE_AID_32 - use the full 32 IDs (5 ID bits)
|
||||
* KBASE_AID_16 - use 16 IDs (4 ID bits)
|
||||
* KBASE_AID_8 - use 8 IDs (3 ID bits)
|
||||
* KBASE_AID_4 - use 4 IDs (2 ID bits)
|
||||
* Default value: KBASE_AID_32 (no limit). Note hardware implementation
|
||||
* may limit to a lower value.
|
||||
*/
|
||||
#define DEFAULT_ARID_LIMIT KBASE_AID_32
|
||||
|
||||
/**
|
||||
* Default setting for write Address ID limiting on AXI.
|
||||
*
|
||||
* Attached value: u32 register value
|
||||
* KBASE_AID_32 - use the full 32 IDs (5 ID bits)
|
||||
* KBASE_AID_16 - use 16 IDs (4 ID bits)
|
||||
* KBASE_AID_8 - use 8 IDs (3 ID bits)
|
||||
* KBASE_AID_4 - use 4 IDs (2 ID bits)
|
||||
* Default value: KBASE_AID_32 (no limit). Note hardware implementation
|
||||
* may limit to a lower value.
|
||||
*/
|
||||
#define DEFAULT_AWID_LIMIT KBASE_AID_32
|
||||
|
||||
/**
|
||||
* Default setting for using alternative hardware counters.
|
||||
*/
|
||||
#define DEFAULT_ALTERNATIVE_HWC false
|
||||
|
||||
/**
|
||||
* Default UMP device mapping. A UMP_DEVICE_<device>_SHIFT value which
|
||||
* defines which UMP device this GPU should be mapped to.
|
||||
*/
|
||||
#define DEFAULT_UMP_GPU_DEVICE_SHIFT UMP_DEVICE_Z_SHIFT
|
||||
|
||||
/*
|
||||
* Default period for DVFS sampling
|
||||
*/
|
||||
#define DEFAULT_PM_DVFS_PERIOD 100 /* 100ms */
|
||||
|
||||
/*
|
||||
* Power Management poweroff tick granuality. This is in nanoseconds to
|
||||
* allow HR timer support.
|
||||
*
|
||||
* On each scheduling tick, the power manager core may decide to:
|
||||
* -# Power off one or more shader cores
|
||||
* -# Power off the entire GPU
|
||||
*/
|
||||
#define DEFAULT_PM_GPU_POWEROFF_TICK_NS (400000) /* 400us */
|
||||
|
||||
/*
|
||||
* Power Manager number of ticks before shader cores are powered off
|
||||
*/
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define DEFAULT_PM_POWEROFF_TICK_SHADER (0) /* 400-800us */
|
||||
|
||||
/*
|
||||
* Power Manager number of ticks before GPU is powered off
|
||||
*/
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define DEFAULT_PM_POWEROFF_TICK_GPU (0) /* 400-800us */
|
||||
|
||||
/*
|
||||
* Default scheduling tick granuality
|
||||
*/
|
||||
#define DEFAULT_JS_SCHEDULING_PERIOD_NS (100000000u) /* 100ms */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before jobs are soft-stopped.
|
||||
*
|
||||
* This defines the time-slice for a job (which may be different from that of a
|
||||
* context)
|
||||
*/
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define DEFAULT_JS_SOFT_STOP_TICKS (20) /* 2000ms */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before CL jobs are soft-stopped.
|
||||
*/
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#define DEFAULT_JS_SOFT_STOP_TICKS_CL (20) /* 2000ms */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before jobs are hard-stopped
|
||||
*/
|
||||
#define DEFAULT_JS_HARD_STOP_TICKS_SS (50) /* 5s */
|
||||
#define DEFAULT_JS_HARD_STOP_TICKS_SS_8408 (300) /* 30s */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before CL jobs are hard-stopped.
|
||||
*/
|
||||
#define DEFAULT_JS_HARD_STOP_TICKS_CL (50) /* 5s */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before jobs are hard-stopped
|
||||
* during dumping
|
||||
*/
|
||||
#define DEFAULT_JS_HARD_STOP_TICKS_DUMPING (15000) /* 1500s */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before the GPU is reset to clear a
|
||||
* "stuck" job
|
||||
*/
|
||||
#define DEFAULT_JS_RESET_TICKS_SS (55) /* 5.5s */
|
||||
#define DEFAULT_JS_RESET_TICKS_SS_8408 (450) /* 45s */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before the GPU is reset to clear a
|
||||
* "stuck" CL job.
|
||||
*/
|
||||
#define DEFAULT_JS_RESET_TICKS_CL (55) /* 5.5s */
|
||||
|
||||
/*
|
||||
* Default minimum number of scheduling ticks before the GPU is reset to clear a
|
||||
* "stuck" job during dumping.
|
||||
*/
|
||||
#define DEFAULT_JS_RESET_TICKS_DUMPING (15020) /* 1502s */
|
||||
|
||||
/*
|
||||
* Default number of milliseconds given for other jobs on the GPU to be
|
||||
* soft-stopped when the GPU needs to be reset.
|
||||
*/
|
||||
#define DEFAULT_RESET_TIMEOUT_MS (3000) /* 3s */
|
||||
|
||||
/*
|
||||
* Default timeslice that a context is scheduled in for, in nanoseconds.
|
||||
*
|
||||
* When a context has used up this amount of time across its jobs, it is
|
||||
* scheduled out to let another run.
|
||||
*
|
||||
* @note the resolution is nanoseconds (ns) here, because that's the format
|
||||
* often used by the OS.
|
||||
*/
|
||||
#define DEFAULT_JS_CTX_TIMESLICE_NS (50000000) /* 50ms */
|
||||
|
||||
#endif /* _KBASE_CONFIG_DEFAULTS_H_ */
|
||||
|
||||
321
drivers/gpu/arm/t72x/r7p0/mali_kbase_context.c
Normal file
321
drivers/gpu/arm/t72x/r7p0/mali_kbase_context.c
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel context APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <mali_kbase_instr.h>
|
||||
|
||||
|
||||
/**
|
||||
* kbase_create_context() - Create a kernel base context.
|
||||
* @kbdev: Kbase device
|
||||
* @is_compat: Force creation of a 32-bit context
|
||||
*
|
||||
* Allocate and init a kernel base context.
|
||||
*
|
||||
* Return: new kbase context
|
||||
*/
|
||||
struct kbase_context *
|
||||
kbase_create_context(struct kbase_device *kbdev, bool is_compat)
|
||||
{
|
||||
struct kbase_context *kctx;
|
||||
int err;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
/* zero-inited as lot of code assume it's zero'ed out on create */
|
||||
kctx = vzalloc(sizeof(*kctx));
|
||||
|
||||
if (!kctx)
|
||||
goto out;
|
||||
|
||||
/* creating a context is considered a disjoint event */
|
||||
kbase_disjoint_event(kbdev);
|
||||
|
||||
kctx->kbdev = kbdev;
|
||||
kctx->as_nr = KBASEP_AS_NR_INVALID;
|
||||
kctx->is_compat = is_compat;
|
||||
#ifdef CONFIG_MALI_TRACE_TIMELINE
|
||||
kctx->timeline.owner_tgid = task_tgid_nr(current);
|
||||
#endif
|
||||
atomic_set(&kctx->setup_complete, 0);
|
||||
atomic_set(&kctx->setup_in_progress, 0);
|
||||
kctx->infinite_cache_active = 0;
|
||||
spin_lock_init(&kctx->mm_update_lock);
|
||||
kctx->process_mm = NULL;
|
||||
atomic_set(&kctx->nonmapped_pages, 0);
|
||||
kctx->slots_pullable = 0;
|
||||
|
||||
err = kbase_mem_pool_init(&kctx->mem_pool,
|
||||
kbdev->mem_pool_max_size_default,
|
||||
kctx->kbdev, &kbdev->mem_pool);
|
||||
if (err)
|
||||
goto free_kctx;
|
||||
|
||||
atomic_set(&kctx->used_pages, 0);
|
||||
|
||||
err = kbase_jd_init(kctx);
|
||||
if (err)
|
||||
goto free_pool;
|
||||
|
||||
err = kbasep_js_kctx_init(kctx);
|
||||
if (err)
|
||||
goto free_jd; /* safe to call kbasep_js_kctx_term in this case */
|
||||
|
||||
err = kbase_event_init(kctx);
|
||||
if (err)
|
||||
goto free_jd;
|
||||
|
||||
mutex_init(&kctx->reg_lock);
|
||||
|
||||
INIT_LIST_HEAD(&kctx->waiting_soft_jobs);
|
||||
#ifdef CONFIG_KDS
|
||||
INIT_LIST_HEAD(&kctx->waiting_kds_resource);
|
||||
#endif
|
||||
|
||||
err = kbase_mmu_init(kctx);
|
||||
if (err)
|
||||
goto free_event;
|
||||
|
||||
kctx->pgd = kbase_mmu_alloc_pgd(kctx);
|
||||
if (!kctx->pgd)
|
||||
goto free_mmu;
|
||||
|
||||
kctx->aliasing_sink_page = kbase_mem_pool_alloc(&kctx->mem_pool);
|
||||
if (!kctx->aliasing_sink_page)
|
||||
goto no_sink_page;
|
||||
|
||||
kctx->tgid = current->tgid;
|
||||
kctx->pid = current->pid;
|
||||
init_waitqueue_head(&kctx->event_queue);
|
||||
|
||||
kctx->cookies = KBASE_COOKIE_MASK;
|
||||
|
||||
/* Make sure page 0 is not used... */
|
||||
err = kbase_region_tracker_init(kctx);
|
||||
if (err)
|
||||
goto no_region_tracker;
|
||||
#ifdef CONFIG_GPU_TRACEPOINTS
|
||||
atomic_set(&kctx->jctx.work_id, 0);
|
||||
#endif
|
||||
#ifdef CONFIG_MALI_TRACE_TIMELINE
|
||||
atomic_set(&kctx->timeline.jd_atoms_in_flight, 0);
|
||||
#endif
|
||||
|
||||
kctx->id = atomic_add_return(1, &(kbdev->ctx_num)) - 1;
|
||||
|
||||
mutex_init(&kctx->vinstr_cli_lock);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if (kbdev->vendor_callbacks->create_context)
|
||||
kbdev->vendor_callbacks->create_context(kctx);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
atomic_set(&kctx->mem_profile_showing_state, 0);
|
||||
init_waitqueue_head(&kctx->mem_profile_wait);
|
||||
|
||||
return kctx;
|
||||
|
||||
no_region_tracker:
|
||||
kbase_mem_pool_free(&kctx->mem_pool, kctx->aliasing_sink_page, false);
|
||||
no_sink_page:
|
||||
/* VM lock needed for the call to kbase_mmu_free_pgd */
|
||||
kbase_gpu_vm_lock(kctx);
|
||||
kbase_mmu_free_pgd(kctx);
|
||||
kbase_gpu_vm_unlock(kctx);
|
||||
free_mmu:
|
||||
kbase_mmu_term(kctx);
|
||||
free_event:
|
||||
kbase_event_cleanup(kctx);
|
||||
free_jd:
|
||||
/* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */
|
||||
kbasep_js_kctx_term(kctx);
|
||||
kbase_jd_exit(kctx);
|
||||
free_pool:
|
||||
kbase_mem_pool_term(&kctx->mem_pool);
|
||||
free_kctx:
|
||||
vfree(kctx);
|
||||
out:
|
||||
return NULL;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_create_context);
|
||||
|
||||
static void kbase_reg_pending_dtor(struct kbase_va_region *reg)
|
||||
{
|
||||
dev_dbg(reg->kctx->kbdev->dev, "Freeing pending unmapped region\n");
|
||||
kbase_mem_phy_alloc_put(reg->cpu_alloc);
|
||||
kbase_mem_phy_alloc_put(reg->gpu_alloc);
|
||||
kfree(reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_destroy_context - Destroy a kernel base context.
|
||||
* @kctx: Context to destroy
|
||||
*
|
||||
* Calls kbase_destroy_os_context() to free OS specific structures.
|
||||
* Will release all outstanding regions.
|
||||
*/
|
||||
void kbase_destroy_context(struct kbase_context *kctx)
|
||||
{
|
||||
struct kbase_device *kbdev;
|
||||
int pages;
|
||||
unsigned long pending_regions_to_clean;
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
int profile_count;
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if (!kctx) {
|
||||
printk("An uninitialized or destroyed context is tried to be destroyed. kctx is null\n");
|
||||
return ;
|
||||
}
|
||||
else if (kctx->ctx_status != CTX_INITIALIZED) {
|
||||
printk("An uninitialized or destroyed context is tried to be destroyed\n");
|
||||
printk("kctx: 0x%p, kctx->tgid: %d, kctx->ctx_status: 0x%x\n", kctx, kctx->tgid, kctx->ctx_status);
|
||||
return ;
|
||||
}
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kctx);
|
||||
|
||||
kbdev = kctx->kbdev;
|
||||
KBASE_DEBUG_ASSERT(NULL != kbdev);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
for (profile_count = 0; profile_count < 3; profile_count++) {
|
||||
if (wait_event_timeout(kctx->mem_profile_wait, atomic_read(&kctx->mem_profile_showing_state) == 0, (unsigned int) msecs_to_jiffies(1000)))
|
||||
break;
|
||||
else
|
||||
printk("[G3D] waiting for memory profile\n");
|
||||
}
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
while (wait_event_timeout(kbdev->pm.suspending_wait, kbdev->pm.suspending == false, (unsigned int) msecs_to_jiffies(1000)) == 0)
|
||||
printk("[G3D] Waiting for resuming the device\n");
|
||||
|
||||
KBASE_TRACE_ADD(kbdev, CORE_CTX_DESTROY, kctx, NULL, 0u, 0u);
|
||||
|
||||
/* Ensure the core is powered up for the destroy process */
|
||||
/* A suspend won't happen here, because we're in a syscall from a userspace
|
||||
* thread. */
|
||||
kbase_pm_context_active(kbdev);
|
||||
|
||||
kbase_jd_zap_context(kctx);
|
||||
kbase_event_cleanup(kctx);
|
||||
|
||||
kbase_gpu_vm_lock(kctx);
|
||||
|
||||
/* MMU is disabled as part of scheduling out the context */
|
||||
kbase_mmu_free_pgd(kctx);
|
||||
|
||||
/* drop the aliasing sink page now that it can't be mapped anymore */
|
||||
kbase_mem_pool_free(&kctx->mem_pool, kctx->aliasing_sink_page, false);
|
||||
|
||||
/* free pending region setups */
|
||||
pending_regions_to_clean = (~kctx->cookies) & KBASE_COOKIE_MASK;
|
||||
while (pending_regions_to_clean) {
|
||||
unsigned int cookie = __ffs(pending_regions_to_clean);
|
||||
|
||||
BUG_ON(!kctx->pending_regions[cookie]);
|
||||
|
||||
kbase_reg_pending_dtor(kctx->pending_regions[cookie]);
|
||||
|
||||
kctx->pending_regions[cookie] = NULL;
|
||||
pending_regions_to_clean &= ~(1UL << cookie);
|
||||
}
|
||||
|
||||
kbase_region_tracker_term(kctx);
|
||||
kbase_gpu_vm_unlock(kctx);
|
||||
|
||||
/* Safe to call this one even when didn't initialize (assuming kctx was sufficiently zeroed) */
|
||||
kbasep_js_kctx_term(kctx);
|
||||
|
||||
kbase_jd_exit(kctx);
|
||||
|
||||
kbase_pm_context_idle(kbdev);
|
||||
|
||||
kbase_mmu_term(kctx);
|
||||
|
||||
pages = atomic_read(&kctx->used_pages);
|
||||
if (pages != 0)
|
||||
dev_warn(kbdev->dev, "%s: %d pages in use!\n", __func__, pages);
|
||||
|
||||
kbase_mem_pool_term(&kctx->mem_pool);
|
||||
WARN_ON(atomic_read(&kctx->nonmapped_pages) != 0);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if(kbdev->vendor_callbacks->destroy_context)
|
||||
kbdev->vendor_callbacks->destroy_context(kctx);
|
||||
|
||||
if (kctx->ctx_need_qos) {
|
||||
kctx->ctx_need_qos = false;
|
||||
}
|
||||
|
||||
vfree(kctx);
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
kctx = NULL;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_destroy_context);
|
||||
|
||||
/**
|
||||
* kbase_context_set_create_flags - Set creation flags on a context
|
||||
* @kctx: Kbase context
|
||||
* @flags: Flags to set
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_context_set_create_flags(struct kbase_context *kctx, u32 flags)
|
||||
{
|
||||
int err = 0;
|
||||
struct kbasep_js_kctx_info *js_kctx_info;
|
||||
unsigned long irq_flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kctx);
|
||||
|
||||
js_kctx_info = &kctx->jctx.sched_info;
|
||||
|
||||
/* Validate flags */
|
||||
if (flags != (flags & BASE_CONTEXT_CREATE_KERNEL_FLAGS)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
spin_lock_irqsave(&kctx->kbdev->js_data.runpool_irq.lock, irq_flags);
|
||||
|
||||
/* Translate the flags */
|
||||
if ((flags & BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) == 0)
|
||||
js_kctx_info->ctx.flags &= ~((u32) KBASE_CTX_FLAG_SUBMIT_DISABLED);
|
||||
|
||||
if ((flags & BASE_CONTEXT_HINT_ONLY_COMPUTE) != 0)
|
||||
js_kctx_info->ctx.flags |= (u32) KBASE_CTX_FLAG_HINT_ONLY_COMPUTE;
|
||||
|
||||
/* Latch the initial attributes into the Job Scheduler */
|
||||
kbasep_js_ctx_attr_set_initial_attrs(kctx->kbdev, kctx);
|
||||
|
||||
spin_unlock_irqrestore(&kctx->kbdev->js_data.runpool_irq.lock,
|
||||
irq_flags);
|
||||
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_context_set_create_flags);
|
||||
4253
drivers/gpu/arm/t72x/r7p0/mali_kbase_core_linux.c
Normal file
4253
drivers/gpu/arm/t72x/r7p0/mali_kbase_core_linux.c
Normal file
File diff suppressed because it is too large
Load diff
125
drivers/gpu/arm/t72x/r7p0/mali_kbase_cpuprops.c
Normal file
125
drivers/gpu/arm/t72x/r7p0/mali_kbase_cpuprops.c
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel property query APIs
|
||||
*/
|
||||
|
||||
#include "mali_kbase.h"
|
||||
#ifdef BASE_LEGACY_UK7_SUPPORT
|
||||
|
||||
#include "mali_kbase_cpuprops.h"
|
||||
#include "mali_kbase_uku.h"
|
||||
#include <mali_kbase_config.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
#include <linux/cache.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
||||
#include <asm/cputype.h>
|
||||
#endif
|
||||
|
||||
#define KBASE_DEFAULT_CPU_NUM 0
|
||||
|
||||
#define L1_DCACHE_LINE_SIZE_LOG2 L1_CACHE_SHIFT
|
||||
|
||||
/*
|
||||
* Macros used to extract cpu id info
|
||||
* see documentation for Main ID register
|
||||
*/
|
||||
#define KBASE_CPUPROPS_ID_GET_REV(cpuid) ((cpuid) & 0x0F) /* [3:0] Revision */
|
||||
#define KBASE_CPUPROPS_ID_GET_PART_NR(cpuid)(((cpuid) >> 4) & 0xFFF) /* [15:4] Part number */
|
||||
#define KBASE_CPUPROPS_ID_GET_ARCH(cpuid) (((cpuid) >> 16) & 0x0F) /* [19:16] Architecture */
|
||||
#define KBASE_CPUPROPS_ID_GET_VARIANT(cpuid)(((cpuid) >> 20) & 0x0F) /* [23:20] Variant */
|
||||
#define KBASE_CPUPROPS_ID_GET_CODE(cpuid) (((cpuid) >> 24) & 0xFF) /* [31:23] ASCII code of implementer trademark */
|
||||
|
||||
/*Below value sourced from OSK*/
|
||||
#define L1_DCACHE_SIZE ((u32)0x00008000)
|
||||
|
||||
/**
|
||||
* kbasep_cpuprops_uk_get_cpu_id_info - Retrieves detailed CPU info from given
|
||||
* cpu_val ( ID reg )
|
||||
* @kbase_props: CPU props to be filled-in with cpu id info
|
||||
*
|
||||
*/
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
||||
static void kbasep_cpuprops_uk_get_cpu_id_info(struct kbase_uk_cpuprops * const kbase_props)
|
||||
{
|
||||
kbase_props->props.cpu_id.id = read_cpuid_id();
|
||||
|
||||
kbase_props->props.cpu_id.valid = 1;
|
||||
kbase_props->props.cpu_id.rev = KBASE_CPUPROPS_ID_GET_REV(kbase_props->props.cpu_id.id);
|
||||
kbase_props->props.cpu_id.part = KBASE_CPUPROPS_ID_GET_PART_NR(kbase_props->props.cpu_id.id);
|
||||
kbase_props->props.cpu_id.arch = KBASE_CPUPROPS_ID_GET_ARCH(kbase_props->props.cpu_id.id);
|
||||
kbase_props->props.cpu_id.variant = KBASE_CPUPROPS_ID_GET_VARIANT(kbase_props->props.cpu_id.id);
|
||||
kbase_props->props.cpu_id.implementer = KBASE_CPUPROPS_ID_GET_CODE(kbase_props->props.cpu_id.id);
|
||||
}
|
||||
#else
|
||||
static void kbasep_cpuprops_uk_get_cpu_id_info(struct kbase_uk_cpuprops * const kbase_props)
|
||||
{
|
||||
kbase_props->props.cpu_id.id = 0;
|
||||
kbase_props->props.cpu_id.valid = 0;
|
||||
kbase_props->props.cpu_id.rev = 0;
|
||||
kbase_props->props.cpu_id.part = 0;
|
||||
kbase_props->props.cpu_id.arch = 0;
|
||||
kbase_props->props.cpu_id.variant = 0;
|
||||
kbase_props->props.cpu_id.implementer = 'N';
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function (and file!) is kept for the backward compatibility reasons.
|
||||
* It shall be removed as soon as KBASE_FUNC_CPU_PROPS_REG_DUMP_OBSOLETE
|
||||
* (previously KBASE_FUNC_CPU_PROPS_REG_DUMP) ioctl call
|
||||
* is removed. Removal of KBASE_FUNC_CPU_PROPS_REG_DUMP is part of having
|
||||
* the function for reading cpu properties moved from base to osu.
|
||||
*/
|
||||
|
||||
int kbase_cpuprops_uk_get_props(struct kbase_context *kctx,
|
||||
struct kbase_uk_cpuprops * const props)
|
||||
{
|
||||
unsigned int max_cpu_freq;
|
||||
|
||||
props->props.cpu_l1_dcache_line_size_log2 = L1_DCACHE_LINE_SIZE_LOG2;
|
||||
props->props.cpu_l1_dcache_size = L1_DCACHE_SIZE;
|
||||
props->props.cpu_flags = BASE_CPU_PROPERTY_FLAG_LITTLE_ENDIAN;
|
||||
|
||||
props->props.nr_cores = num_possible_cpus();
|
||||
props->props.cpu_page_size_log2 = PAGE_SHIFT;
|
||||
props->props.available_memory_size = totalram_pages << PAGE_SHIFT;
|
||||
|
||||
kbasep_cpuprops_uk_get_cpu_id_info(props);
|
||||
|
||||
/* check if kernel supports dynamic frequency scaling */
|
||||
max_cpu_freq = cpufreq_quick_get_max(KBASE_DEFAULT_CPU_NUM);
|
||||
if (max_cpu_freq != 0) {
|
||||
/* convert from kHz to mHz */
|
||||
props->props.max_cpu_clock_speed_mhz = max_cpu_freq / 1000;
|
||||
} else {
|
||||
/* fallback if CONFIG_CPU_FREQ turned off */
|
||||
int err;
|
||||
kbase_cpu_clk_speed_func get_clock_speed;
|
||||
|
||||
get_clock_speed = (kbase_cpu_clk_speed_func) CPU_SPEED_FUNC;
|
||||
err = get_clock_speed(&props->props.max_cpu_clock_speed_mhz);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* BASE_LEGACY_UK7_SUPPORT */
|
||||
53
drivers/gpu/arm/t72x/r7p0/mali_kbase_cpuprops.h
Normal file
53
drivers/gpu/arm/t72x/r7p0/mali_kbase_cpuprops.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h"
|
||||
#ifdef BASE_LEGACY_UK7_SUPPORT
|
||||
|
||||
/**
|
||||
* @file mali_kbase_cpuprops.h
|
||||
* Base kernel property query APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_CPUPROPS_H_
|
||||
#define _KBASE_CPUPROPS_H_
|
||||
|
||||
/* Forward declarations */
|
||||
struct kbase_uk_cpuprops;
|
||||
|
||||
/**
|
||||
* This file is kept for the backward compatibility reasons.
|
||||
* It shall be removed as soon as KBASE_FUNC_CPU_PROPS_REG_DUMP_OBSOLETE
|
||||
* (previously KBASE_FUNC_CPU_PROPS_REG_DUMP) ioctl call
|
||||
* is removed. Removal of KBASE_FUNC_CPU_PROPS_REG_DUMP is part of having
|
||||
* the function for reading cpu properties moved from base to osu.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Provides CPU properties data.
|
||||
*
|
||||
* Fill the struct kbase_uk_cpuprops with values from CPU configuration.
|
||||
*
|
||||
* @param kctx The kbase context
|
||||
* @param kbase_props A copy of the struct kbase_uk_cpuprops structure from userspace
|
||||
*
|
||||
* @return 0 on success. Any other value indicates failure.
|
||||
*/
|
||||
int kbase_cpuprops_uk_get_props(struct kbase_context *kctx, struct kbase_uk_cpuprops * const kbase_props);
|
||||
|
||||
#endif /*_KBASE_CPUPROPS_H_*/
|
||||
#endif /* BASE_LEGACY_UK7_SUPPORT */
|
||||
39
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug.c
Normal file
39
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
|
||||
static struct kbasep_debug_assert_cb kbasep_debug_assert_registered_cb = {
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
void kbase_debug_assert_register_hook(kbase_debug_assert_hook *func, void *param)
|
||||
{
|
||||
kbasep_debug_assert_registered_cb.func = func;
|
||||
kbasep_debug_assert_registered_cb.param = param;
|
||||
}
|
||||
|
||||
void kbasep_debug_assert_call_hook(void)
|
||||
{
|
||||
if (kbasep_debug_assert_registered_cb.func != NULL)
|
||||
kbasep_debug_assert_registered_cb.func(kbasep_debug_assert_registered_cb.param);
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbasep_debug_assert_call_hook);
|
||||
|
||||
164
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug.h
Normal file
164
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug.h
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_DEBUG_H
|
||||
#define _KBASE_DEBUG_H
|
||||
|
||||
#include <linux/bug.h>
|
||||
|
||||
/** @brief If equals to 0, a trace containing the file, line, and function will be displayed before each message. */
|
||||
#define KBASE_DEBUG_SKIP_TRACE 0
|
||||
|
||||
/** @brief If different from 0, the trace will only contain the file and line. */
|
||||
#define KBASE_DEBUG_SKIP_FUNCTION_NAME 0
|
||||
|
||||
/** @brief Disable the asserts tests if set to 1. Default is to disable the asserts in release. */
|
||||
#ifndef KBASE_DEBUG_DISABLE_ASSERTS
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#define KBASE_DEBUG_DISABLE_ASSERTS 0
|
||||
#else
|
||||
#define KBASE_DEBUG_DISABLE_ASSERTS 1
|
||||
#endif
|
||||
#endif /* KBASE_DEBUG_DISABLE_ASSERTS */
|
||||
|
||||
/** Function type that is called on an KBASE_DEBUG_ASSERT() or KBASE_DEBUG_ASSERT_MSG() */
|
||||
typedef void (kbase_debug_assert_hook) (void *);
|
||||
|
||||
struct kbasep_debug_assert_cb {
|
||||
kbase_debug_assert_hook *func;
|
||||
void *param;
|
||||
};
|
||||
|
||||
/**
|
||||
* @def KBASEP_DEBUG_PRINT_TRACE
|
||||
* @brief Private macro containing the format of the trace to display before every message
|
||||
* @sa KBASE_DEBUG_SKIP_TRACE, KBASE_DEBUG_SKIP_FUNCTION_NAME
|
||||
*/
|
||||
#if !KBASE_DEBUG_SKIP_TRACE
|
||||
#define KBASEP_DEBUG_PRINT_TRACE \
|
||||
"In file: " __FILE__ " line: " CSTD_STR2(__LINE__)
|
||||
#if !KBASE_DEBUG_SKIP_FUNCTION_NAME
|
||||
#define KBASEP_DEBUG_PRINT_FUNCTION __func__
|
||||
#else
|
||||
#define KBASEP_DEBUG_PRINT_FUNCTION ""
|
||||
#endif
|
||||
#else
|
||||
#define KBASEP_DEBUG_PRINT_TRACE ""
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def KBASEP_DEBUG_ASSERT_OUT(trace, function, ...)
|
||||
* @brief (Private) system printing function associated to the @see KBASE_DEBUG_ASSERT_MSG event.
|
||||
* @param trace location in the code from where the message is printed
|
||||
* @param function function from where the message is printed
|
||||
* @param ... Format string followed by format arguments.
|
||||
* @note function parameter cannot be concatenated with other strings
|
||||
*/
|
||||
/* Select the correct system output function*/
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#define KBASEP_DEBUG_ASSERT_OUT(trace, function, ...)\
|
||||
do { \
|
||||
pr_err("Mali<ASSERT>: %s function:%s ", trace, function);\
|
||||
pr_err(__VA_ARGS__);\
|
||||
pr_err("\n");\
|
||||
} while (false)
|
||||
#else
|
||||
#define KBASEP_DEBUG_ASSERT_OUT(trace, function, ...) CSTD_NOP()
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#define KBASE_CALL_ASSERT_HOOK() kbasep_debug_assert_call_hook()
|
||||
#else
|
||||
#define KBASE_CALL_ASSERT_HOOK() CSTD_NOP()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def KBASE_DEBUG_ASSERT(expr)
|
||||
* @brief Calls @see KBASE_PRINT_ASSERT and prints the expression @a expr if @a expr is false
|
||||
*
|
||||
* @note This macro does nothing if the flag @see KBASE_DEBUG_DISABLE_ASSERTS is set to 1
|
||||
*
|
||||
* @param expr Boolean expression
|
||||
*/
|
||||
#define KBASE_DEBUG_ASSERT(expr) \
|
||||
KBASE_DEBUG_ASSERT_MSG(expr, #expr)
|
||||
|
||||
#if KBASE_DEBUG_DISABLE_ASSERTS
|
||||
#define KBASE_DEBUG_ASSERT_MSG(expr, ...) CSTD_NOP()
|
||||
#else
|
||||
/**
|
||||
* @def KBASE_DEBUG_ASSERT_MSG(expr, ...)
|
||||
* @brief Calls @see KBASEP_DEBUG_ASSERT_OUT and prints the given message if @a expr is false
|
||||
*
|
||||
* @note This macro does nothing if the flag @see KBASE_DEBUG_DISABLE_ASSERTS is set to 1
|
||||
*
|
||||
* @param expr Boolean expression
|
||||
* @param ... Message to display when @a expr is false, as a format string followed by format arguments.
|
||||
*/
|
||||
#define KBASE_DEBUG_ASSERT_MSG(expr, ...) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
KBASEP_DEBUG_ASSERT_OUT(KBASEP_DEBUG_PRINT_TRACE, KBASEP_DEBUG_PRINT_FUNCTION, __VA_ARGS__);\
|
||||
KBASE_CALL_ASSERT_HOOK();\
|
||||
BUG();\
|
||||
} \
|
||||
} while (false)
|
||||
#endif /* KBASE_DEBUG_DISABLE_ASSERTS */
|
||||
|
||||
/**
|
||||
* @def KBASE_DEBUG_CODE( X )
|
||||
* @brief Executes the code inside the macro only in debug mode
|
||||
*
|
||||
* @param X Code to compile only in debug mode.
|
||||
*/
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
#define KBASE_DEBUG_CODE(X) X
|
||||
#else
|
||||
#define KBASE_DEBUG_CODE(X) CSTD_NOP()
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Register a function to call on ASSERT
|
||||
*
|
||||
* Such functions will \b only be called during Debug mode, and for debugging
|
||||
* features \b only. Do not rely on them to be called in general use.
|
||||
*
|
||||
* To disable the hook, supply NULL to \a func.
|
||||
*
|
||||
* @note This function is not thread-safe, and should only be used to
|
||||
* register/deregister once in the module's lifetime.
|
||||
*
|
||||
* @param[in] func the function to call when an assert is triggered.
|
||||
* @param[in] param the parameter to pass to \a func when calling it
|
||||
*/
|
||||
void kbase_debug_assert_register_hook(kbase_debug_assert_hook *func, void *param);
|
||||
|
||||
/**
|
||||
* @brief Call a debug assert hook previously registered with kbase_debug_assert_register_hook()
|
||||
*
|
||||
* @note This function is not thread-safe with respect to multiple threads
|
||||
* registering functions and parameters with
|
||||
* kbase_debug_assert_register_hook(). Otherwise, thread safety is the
|
||||
* responsibility of the registered hook.
|
||||
*/
|
||||
void kbasep_debug_assert_call_hook(void);
|
||||
|
||||
#endif /* _KBASE_DEBUG_H */
|
||||
447
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_job_fault.c
Normal file
447
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_job_fault.c
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_debug_job_fault.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static bool kbase_is_job_fault_event_pending(struct list_head *event_list)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
ret = (!list_empty(event_list));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool kbase_ctx_has_no_event_pending(
|
||||
struct kbase_context *kctx, struct list_head *event_list)
|
||||
{
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
if (list_empty(event_list))
|
||||
return true;
|
||||
list_for_each_entry(event, event_list, head) {
|
||||
if (event->katom->kctx == kctx)
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* wait until the fault happen and copy the event */
|
||||
static int kbase_job_fault_event_wait(struct kbase_device *kbdev,
|
||||
struct list_head *event_list,
|
||||
struct base_job_fault_event *event)
|
||||
{
|
||||
struct base_job_fault_event *event_in;
|
||||
|
||||
if (list_empty(event_list)) {
|
||||
if (wait_event_interruptible(kbdev->job_fault_wq,
|
||||
kbase_is_job_fault_event_pending(event_list)))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
event_in = list_entry(event_list->next,
|
||||
struct base_job_fault_event, head);
|
||||
|
||||
event->event_code = event_in->event_code;
|
||||
event->katom = event_in->katom;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* remove the event from the queue */
|
||||
static struct base_job_fault_event *kbase_job_fault_event_dequeue(
|
||||
struct kbase_device *kbdev, struct list_head *event_list)
|
||||
{
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
event = list_entry(event_list->next,
|
||||
struct base_job_fault_event, head);
|
||||
list_del(event_list->next);
|
||||
|
||||
return event;
|
||||
|
||||
}
|
||||
|
||||
/* Remove all the following atoms after the failed atom in the same context
|
||||
* Call the postponed bottom half of job done.
|
||||
* Then, this context could be rescheduled.
|
||||
*/
|
||||
static void kbase_job_fault_resume_event_cleanup(struct kbase_context *kctx)
|
||||
{
|
||||
struct list_head *event_list = &kctx->job_fault_resume_event_list;
|
||||
|
||||
while (!list_empty(event_list)) {
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
event = kbase_job_fault_event_dequeue(kctx->kbdev,
|
||||
&kctx->job_fault_resume_event_list);
|
||||
kbase_jd_done_worker(&event->katom->work);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Remove all the failed atoms that belong to different contexts
|
||||
* Resume all the contexts that were suspend due to failed job
|
||||
*/
|
||||
static void kbase_job_fault_event_cleanup(struct kbase_device *kbdev)
|
||||
{
|
||||
struct list_head *event_list = &kbdev->job_fault_event_list;
|
||||
|
||||
while (!list_empty(event_list)) {
|
||||
|
||||
kbase_job_fault_event_dequeue(kbdev, event_list);
|
||||
wake_up(&kbdev->job_fault_resume_wq);
|
||||
}
|
||||
}
|
||||
|
||||
static void kbase_job_fault_resume_worker(struct work_struct *data)
|
||||
{
|
||||
struct base_job_fault_event *event = container_of(data,
|
||||
struct base_job_fault_event, job_fault_work);
|
||||
struct kbase_context *kctx;
|
||||
struct kbase_jd_atom *katom;
|
||||
|
||||
katom = event->katom;
|
||||
kctx = katom->kctx;
|
||||
|
||||
dev_info(kctx->kbdev->dev, "Job dumping wait\n");
|
||||
|
||||
/* When it was waked up, it need to check if queue is empty or the
|
||||
* failed atom belongs to different context. If yes, wake up. Both
|
||||
* of them mean the failed job has been dumped. Please note, it
|
||||
* should never happen that the job_fault_event_list has the two
|
||||
* atoms belong to the same context.
|
||||
*/
|
||||
wait_event(kctx->kbdev->job_fault_resume_wq,
|
||||
kbase_ctx_has_no_event_pending(kctx,
|
||||
&kctx->kbdev->job_fault_event_list));
|
||||
|
||||
atomic_set(&kctx->job_fault_count, 0);
|
||||
kbase_jd_done_worker(&katom->work);
|
||||
|
||||
/* In case the following atoms were scheduled during failed job dump
|
||||
* the job_done_worker was held. We need to rerun it after the dump
|
||||
* was finished
|
||||
*/
|
||||
kbase_job_fault_resume_event_cleanup(kctx);
|
||||
|
||||
dev_info(kctx->kbdev->dev, "Job dumping finish, resume scheduler\n");
|
||||
}
|
||||
|
||||
static struct base_job_fault_event *kbase_job_fault_event_queue(
|
||||
struct list_head *event_list,
|
||||
struct kbase_jd_atom *atom,
|
||||
u32 completion_code)
|
||||
{
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
event = &atom->fault_event;
|
||||
|
||||
event->katom = atom;
|
||||
event->event_code = completion_code;
|
||||
|
||||
list_add_tail(&event->head, event_list);
|
||||
|
||||
return event;
|
||||
|
||||
}
|
||||
|
||||
static void kbase_job_fault_event_post(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom, u32 completion_code)
|
||||
{
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
event = kbase_job_fault_event_queue(&kbdev->job_fault_event_list,
|
||||
katom, completion_code);
|
||||
|
||||
wake_up_interruptible(&kbdev->job_fault_wq);
|
||||
|
||||
INIT_WORK(&event->job_fault_work, kbase_job_fault_resume_worker);
|
||||
queue_work(kbdev->job_fault_resume_workq, &event->job_fault_work);
|
||||
|
||||
dev_info(katom->kctx->kbdev->dev, "Job fault happen, start dump: %d_%d",
|
||||
katom->kctx->tgid, katom->kctx->id);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* This function will process the job fault
|
||||
* Get the register copy
|
||||
* Send the failed job dump event
|
||||
* Create a Wait queue to wait until the job dump finish
|
||||
*/
|
||||
|
||||
bool kbase_debug_job_fault_process(struct kbase_jd_atom *katom,
|
||||
u32 completion_code)
|
||||
{
|
||||
struct kbase_context *kctx = katom->kctx;
|
||||
|
||||
/* Check if dumping is in the process
|
||||
* only one atom of each context can be dumped at the same time
|
||||
* If the atom belongs to different context, it can be dumped
|
||||
*/
|
||||
if (atomic_read(&kctx->job_fault_count) > 0) {
|
||||
kbase_job_fault_event_queue(
|
||||
&kctx->job_fault_resume_event_list,
|
||||
katom, completion_code);
|
||||
dev_info(kctx->kbdev->dev, "queue:%d\n",
|
||||
kbase_jd_atom_id(kctx, katom));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (kctx->kbdev->job_fault_debug == true) {
|
||||
|
||||
if (completion_code != BASE_JD_EVENT_DONE) {
|
||||
|
||||
if (kbase_job_fault_get_reg_snapshot(kctx) == false) {
|
||||
dev_warn(kctx->kbdev->dev, "get reg dump failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
kbase_job_fault_event_post(kctx->kbdev, katom,
|
||||
completion_code);
|
||||
atomic_inc(&kctx->job_fault_count);
|
||||
dev_info(kctx->kbdev->dev, "post:%d\n",
|
||||
kbase_jd_atom_id(kctx, katom));
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
static int debug_job_fault_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct kbase_device *kbdev = m->private;
|
||||
struct base_job_fault_event *event = (struct base_job_fault_event *)v;
|
||||
struct kbase_context *kctx = event->katom->kctx;
|
||||
int i;
|
||||
|
||||
dev_info(kbdev->dev, "debug job fault seq show:%d_%d, %d",
|
||||
kctx->tgid, kctx->id, event->reg_offset);
|
||||
|
||||
if (kctx->reg_dump == NULL) {
|
||||
dev_warn(kbdev->dev, "reg dump is NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kctx->reg_dump[event->reg_offset] ==
|
||||
REGISTER_DUMP_TERMINATION_FLAG) {
|
||||
/* Return the error here to stop the read. And the
|
||||
* following next() will not be called. The stop can
|
||||
* get the real event resource and release it
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (event->reg_offset == 0)
|
||||
seq_printf(m, "%d_%d\n", kctx->tgid, kctx->id);
|
||||
|
||||
for (i = 0; i < 50; i++) {
|
||||
if (kctx->reg_dump[event->reg_offset] ==
|
||||
REGISTER_DUMP_TERMINATION_FLAG) {
|
||||
break;
|
||||
}
|
||||
seq_printf(m, "%08x: %08x\n",
|
||||
kctx->reg_dump[event->reg_offset],
|
||||
kctx->reg_dump[1+event->reg_offset]);
|
||||
event->reg_offset += 2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void *debug_job_fault_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
struct kbase_device *kbdev = m->private;
|
||||
struct base_job_fault_event *event = (struct base_job_fault_event *)v;
|
||||
|
||||
dev_info(kbdev->dev, "debug job fault seq next:%d, %d",
|
||||
event->reg_offset, (int)*pos);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static void *debug_job_fault_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
struct kbase_device *kbdev = m->private;
|
||||
struct base_job_fault_event *event;
|
||||
|
||||
dev_info(kbdev->dev, "fault job seq start:%d", (int)*pos);
|
||||
|
||||
/* The condition is trick here. It needs make sure the
|
||||
* fault hasn't happened and the dumping hasn't been started,
|
||||
* or the dumping has finished
|
||||
*/
|
||||
if (*pos == 0) {
|
||||
event = kmalloc(sizeof(*event), GFP_KERNEL);
|
||||
event->reg_offset = 0;
|
||||
if (kbase_job_fault_event_wait(kbdev,
|
||||
&kbdev->job_fault_event_list, event)) {
|
||||
kfree(event);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The cache flush workaround is called in bottom half of
|
||||
* job done but we delayed it. Now we should clean cache
|
||||
* earlier. Then the GPU memory dump should be correct.
|
||||
*/
|
||||
if (event->katom->need_cache_flush_cores_retained) {
|
||||
kbase_gpu_cacheclean(kbdev, event->katom);
|
||||
event->katom->need_cache_flush_cores_retained = 0;
|
||||
}
|
||||
|
||||
} else
|
||||
return NULL;
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
static void debug_job_fault_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
struct kbase_device *kbdev = m->private;
|
||||
|
||||
/* here we wake up the kbase_jd_done_worker after stop, it needs
|
||||
* get the memory dump before the register dump in debug daemon,
|
||||
* otherwise, the memory dump may be incorrect.
|
||||
*/
|
||||
|
||||
if (v != NULL) {
|
||||
kfree(v);
|
||||
dev_info(kbdev->dev, "debug job fault seq stop stage 1");
|
||||
|
||||
} else {
|
||||
if (!list_empty(&kbdev->job_fault_event_list)) {
|
||||
kbase_job_fault_event_dequeue(kbdev,
|
||||
&kbdev->job_fault_event_list);
|
||||
wake_up(&kbdev->job_fault_resume_wq);
|
||||
}
|
||||
dev_info(kbdev->dev, "debug job fault seq stop stage 2");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const struct seq_operations ops = {
|
||||
.start = debug_job_fault_start,
|
||||
.next = debug_job_fault_next,
|
||||
.stop = debug_job_fault_stop,
|
||||
.show = debug_job_fault_show,
|
||||
};
|
||||
|
||||
static int debug_job_fault_open(struct inode *in, struct file *file)
|
||||
{
|
||||
struct kbase_device *kbdev = in->i_private;
|
||||
|
||||
seq_open(file, &ops);
|
||||
|
||||
((struct seq_file *)file->private_data)->private = kbdev;
|
||||
dev_info(kbdev->dev, "debug job fault seq open");
|
||||
|
||||
kbdev->job_fault_debug = true;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int debug_job_fault_release(struct inode *in, struct file *file)
|
||||
{
|
||||
struct kbase_device *kbdev = in->i_private;
|
||||
|
||||
seq_release(in, file);
|
||||
|
||||
kbdev->job_fault_debug = false;
|
||||
|
||||
/* Clean the unprocessed job fault. After that, all the suspended
|
||||
* contexts could be rescheduled.
|
||||
*/
|
||||
kbase_job_fault_event_cleanup(kbdev);
|
||||
|
||||
dev_info(kbdev->dev, "debug job fault seq close");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations kbasep_debug_job_fault_fops = {
|
||||
.open = debug_job_fault_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = debug_job_fault_release,
|
||||
};
|
||||
|
||||
static int kbase_job_fault_event_init(struct kbase_device *kbdev)
|
||||
{
|
||||
|
||||
INIT_LIST_HEAD(&kbdev->job_fault_event_list);
|
||||
|
||||
init_waitqueue_head(&(kbdev->job_fault_wq));
|
||||
init_waitqueue_head(&(kbdev->job_fault_resume_wq));
|
||||
|
||||
kbdev->job_fault_resume_workq = alloc_workqueue(
|
||||
"kbase_job_fault_resume_work_queue", WQ_MEM_RECLAIM, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize debugfs entry for job fault dump
|
||||
*/
|
||||
void kbase_debug_job_fault_dev_init(struct kbase_device *kbdev)
|
||||
{
|
||||
debugfs_create_file("job_fault", S_IRUGO,
|
||||
kbdev->mali_debugfs_directory, kbdev,
|
||||
&kbasep_debug_job_fault_fops);
|
||||
|
||||
kbase_job_fault_event_init(kbdev);
|
||||
kbdev->job_fault_debug = false;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the relevant data structure per context
|
||||
*/
|
||||
void kbase_debug_job_fault_context_init(struct kbase_context *kctx)
|
||||
{
|
||||
|
||||
/* We need allocate double size register range
|
||||
* Because this memory will keep the register address and value
|
||||
*/
|
||||
kctx->reg_dump = kmalloc(0x4000 * 2, GFP_KERNEL);
|
||||
if (kctx->reg_dump == NULL)
|
||||
return;
|
||||
|
||||
if (kbase_debug_job_fault_reg_snapshot_init(kctx, 0x4000) == false) {
|
||||
kfree(kctx->reg_dump);
|
||||
kctx->reg_dump = NULL;
|
||||
}
|
||||
INIT_LIST_HEAD(&kctx->job_fault_resume_event_list);
|
||||
atomic_set(&kctx->job_fault_count, 0);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* release the relevant resource per context
|
||||
*/
|
||||
void kbase_debug_job_fault_context_exit(struct kbase_context *kctx)
|
||||
{
|
||||
kfree(kctx->reg_dump);
|
||||
}
|
||||
|
||||
#endif
|
||||
82
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_job_fault.h
Normal file
82
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_job_fault.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_DEBUG_JOB_FAULT_H
|
||||
#define _KBASE_DEBUG_JOB_FAULT_H
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#define REGISTER_DUMP_TERMINATION_FLAG 0xFFFFFFFF
|
||||
|
||||
/**
|
||||
* kbase_debug_job_fault_dev_init - Initialize job fault debug sysfs
|
||||
* and create the fault event wait queue per device
|
||||
* @kbdev: Device pointer
|
||||
*/
|
||||
void kbase_debug_job_fault_dev_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_debug_job_fault_context_init - Initialize the relevant
|
||||
* data structure per context
|
||||
* @kctx: KBase context pointer
|
||||
*/
|
||||
void kbase_debug_job_fault_context_init(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_debug_job_fault_context_exit - Release the relevant
|
||||
* resource per context
|
||||
* @kctx: KBase context pointer
|
||||
*/
|
||||
void kbase_debug_job_fault_context_exit(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_debug_job_fault_process - Process the failed job.
|
||||
* It will send a event and wake up the job fault waiting queue
|
||||
* Then create a work queue to wait for job dump finish
|
||||
* This function should be called in the interrupt handler and before
|
||||
* jd_done that make sure the jd_done_worker will be delayed until the
|
||||
* job dump finish
|
||||
* @katom: The failed atom pointer
|
||||
* @completion_code: the job status
|
||||
* @return true if dump is going on
|
||||
*/
|
||||
bool kbase_debug_job_fault_process(struct kbase_jd_atom *katom,
|
||||
u32 completion_code);
|
||||
|
||||
|
||||
/**
|
||||
* kbase_debug_job_fault_reg_snapshot_init - Set the interested registers
|
||||
* address during the job fault process, the relevant registers will
|
||||
* be saved when a job fault happen
|
||||
* @kctx: KBase context pointer
|
||||
* @reg_range: Maximum register address space
|
||||
* @return true if initializing successfully
|
||||
*/
|
||||
bool kbase_debug_job_fault_reg_snapshot_init(struct kbase_context *kctx,
|
||||
int reg_range);
|
||||
|
||||
/**
|
||||
* kbase_job_fault_get_reg_snapshot - Read the interested registers for
|
||||
* failed job dump
|
||||
* @kctx: KBase context pointer
|
||||
* @return true if getting registers successfully
|
||||
*/
|
||||
bool kbase_job_fault_get_reg_snapshot(struct kbase_context *kctx);
|
||||
|
||||
#endif /*_KBASE_DEBUG_JOB_FAULT_H*/
|
||||
251
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_mem_view.c
Normal file
251
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_mem_view.c
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Debugfs interface to dump the memory visible to the GPU
|
||||
*/
|
||||
|
||||
#include "mali_kbase_debug_mem_view.h"
|
||||
#include "mali_kbase.h"
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
struct debug_mem_mapping {
|
||||
struct list_head node;
|
||||
|
||||
struct kbase_mem_phy_alloc *alloc;
|
||||
unsigned long flags;
|
||||
|
||||
u64 start_pfn;
|
||||
size_t nr_pages;
|
||||
};
|
||||
|
||||
struct debug_mem_data {
|
||||
struct list_head mapping_list;
|
||||
struct kbase_context *kctx;
|
||||
};
|
||||
|
||||
struct debug_mem_seq_off {
|
||||
struct list_head *lh;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
static void *debug_mem_start(struct seq_file *m, loff_t *_pos)
|
||||
{
|
||||
struct debug_mem_data *mem_data = m->private;
|
||||
struct debug_mem_seq_off *data;
|
||||
struct debug_mem_mapping *map;
|
||||
loff_t pos = *_pos;
|
||||
|
||||
list_for_each_entry(map, &mem_data->mapping_list, node) {
|
||||
if (pos >= map->nr_pages) {
|
||||
pos -= map->nr_pages;
|
||||
} else {
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return NULL;
|
||||
data->lh = &map->node;
|
||||
data->offset = pos;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
/* Beyond the end */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void debug_mem_stop(struct seq_file *m, void *v)
|
||||
{
|
||||
kfree(v);
|
||||
}
|
||||
|
||||
static void *debug_mem_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
struct debug_mem_data *mem_data = m->private;
|
||||
struct debug_mem_seq_off *data = v;
|
||||
struct debug_mem_mapping *map;
|
||||
|
||||
map = list_entry(data->lh, struct debug_mem_mapping, node);
|
||||
|
||||
if (data->offset < map->nr_pages - 1) {
|
||||
data->offset++;
|
||||
++*pos;
|
||||
return data;
|
||||
}
|
||||
|
||||
if (list_is_last(data->lh, &mem_data->mapping_list))
|
||||
return NULL;
|
||||
|
||||
data->lh = data->lh->next;
|
||||
data->offset = 0;
|
||||
++*pos;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int debug_mem_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct debug_mem_data *mem_data = m->private;
|
||||
struct debug_mem_seq_off *data = v;
|
||||
struct debug_mem_mapping *map;
|
||||
int i, j;
|
||||
struct page *page;
|
||||
uint32_t *mapping;
|
||||
pgprot_t prot = PAGE_KERNEL;
|
||||
|
||||
map = list_entry(data->lh, struct debug_mem_mapping, node);
|
||||
|
||||
kbase_gpu_vm_lock(mem_data->kctx);
|
||||
|
||||
if (data->offset >= map->alloc->nents) {
|
||||
seq_printf(m, "%016llx: Unbacked page\n\n", (map->start_pfn +
|
||||
data->offset) << PAGE_SHIFT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(map->flags & KBASE_REG_CPU_CACHED))
|
||||
prot = pgprot_writecombine(prot);
|
||||
|
||||
page = pfn_to_page(PFN_DOWN(map->alloc->pages[data->offset]));
|
||||
mapping = vmap(&page, 1, VM_MAP, prot);
|
||||
|
||||
for (i = 0; i < PAGE_SIZE; i += 4*sizeof(*mapping)) {
|
||||
seq_printf(m, "%016llx:", i + ((map->start_pfn +
|
||||
data->offset) << PAGE_SHIFT));
|
||||
|
||||
for (j = 0; j < 4*sizeof(*mapping); j += sizeof(*mapping))
|
||||
seq_printf(m, " %08x", mapping[(i+j)/sizeof(*mapping)]);
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
vunmap(mapping);
|
||||
|
||||
seq_putc(m, '\n');
|
||||
|
||||
out:
|
||||
kbase_gpu_vm_unlock(mem_data->kctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations ops = {
|
||||
.start = debug_mem_start,
|
||||
.next = debug_mem_next,
|
||||
.stop = debug_mem_stop,
|
||||
.show = debug_mem_show,
|
||||
};
|
||||
|
||||
static int debug_mem_open(struct inode *i, struct file *file)
|
||||
{
|
||||
struct file *kctx_file = i->i_private;
|
||||
struct kbase_context *kctx = kctx_file->private_data;
|
||||
struct rb_node *p;
|
||||
struct debug_mem_data *mem_data;
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &ops);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem_data = kmalloc(sizeof(*mem_data), GFP_KERNEL);
|
||||
mem_data->kctx = kctx;
|
||||
|
||||
INIT_LIST_HEAD(&mem_data->mapping_list);
|
||||
|
||||
get_file(kctx_file);
|
||||
|
||||
kbase_gpu_vm_lock(kctx);
|
||||
|
||||
for (p = rb_first(&kctx->reg_rbtree); p; p = rb_next(p)) {
|
||||
struct kbase_va_region *reg;
|
||||
struct debug_mem_mapping *mapping;
|
||||
|
||||
reg = rb_entry(p, struct kbase_va_region, rblink);
|
||||
|
||||
if (reg->gpu_alloc == NULL)
|
||||
/* Empty region - ignore */
|
||||
continue;
|
||||
|
||||
mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
|
||||
|
||||
mapping->alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc);
|
||||
mapping->start_pfn = reg->start_pfn;
|
||||
mapping->nr_pages = reg->nr_pages;
|
||||
mapping->flags = reg->flags;
|
||||
list_add_tail(&mapping->node, &mem_data->mapping_list);
|
||||
}
|
||||
|
||||
kbase_gpu_vm_unlock(kctx);
|
||||
|
||||
((struct seq_file *)file->private_data)->private = mem_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int debug_mem_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct file *kctx_file = inode->i_private;
|
||||
struct seq_file *sfile = file->private_data;
|
||||
struct debug_mem_data *mem_data = sfile->private;
|
||||
struct debug_mem_mapping *mapping;
|
||||
|
||||
seq_release(inode, file);
|
||||
|
||||
while (!list_empty(&mem_data->mapping_list)) {
|
||||
mapping = list_first_entry(&mem_data->mapping_list,
|
||||
struct debug_mem_mapping, node);
|
||||
kbase_mem_phy_alloc_put(mapping->alloc);
|
||||
list_del(&mapping->node);
|
||||
kfree(mapping);
|
||||
}
|
||||
|
||||
kfree(mem_data);
|
||||
|
||||
fput(kctx_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations kbase_debug_mem_view_fops = {
|
||||
.open = debug_mem_open,
|
||||
.release = debug_mem_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek
|
||||
};
|
||||
|
||||
/**
|
||||
* kbase_debug_mem_view_init - Initialise the mem_view sysfs file
|
||||
* @kctx_file: The /dev/mali0 file instance for the context
|
||||
*
|
||||
* This function creates a "mem_view" file which can be used to get a view of
|
||||
* the context's memory as the GPU sees it (i.e. using the GPU's page tables).
|
||||
*
|
||||
* The file is cleaned up by a call to debugfs_remove_recursive() deleting the
|
||||
* parent directory.
|
||||
*/
|
||||
void kbase_debug_mem_view_init(struct file *kctx_file)
|
||||
{
|
||||
struct kbase_context *kctx = kctx_file->private_data;
|
||||
|
||||
debugfs_create_file("mem_view", S_IRUGO, kctx->kctx_dentry, kctx_file,
|
||||
&kbase_debug_mem_view_fops);
|
||||
}
|
||||
|
||||
#endif
|
||||
25
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_mem_view.h
Normal file
25
drivers/gpu/arm/t72x/r7p0/mali_kbase_debug_mem_view.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2013-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_DEBUG_MEM_VIEW_H
|
||||
#define _KBASE_DEBUG_MEM_VIEW_H
|
||||
|
||||
#include <mali_kbase.h>
|
||||
|
||||
void kbase_debug_mem_view_init(struct file *kctx_file);
|
||||
|
||||
#endif
|
||||
1342
drivers/gpu/arm/t72x/r7p0/mali_kbase_defs.h
Normal file
1342
drivers/gpu/arm/t72x/r7p0/mali_kbase_defs.h
Normal file
File diff suppressed because it is too large
Load diff
739
drivers/gpu/arm/t72x/r7p0/mali_kbase_device.c
Normal file
739
drivers/gpu/arm/t72x/r7p0/mali_kbase_device.c
Normal file
|
|
@ -0,0 +1,739 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel device APIs
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_kbase_defs.h>
|
||||
#include <mali_kbase_hw.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
|
||||
#include <mali_kbase_profiling_gator_api.h>
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#include "gpu_control.h"
|
||||
|
||||
/* NOTE: Magic - 0x45435254 (TRCE in ASCII).
|
||||
* Supports tracing feature provided in the base module.
|
||||
* Please keep it in sync with the value of base module.
|
||||
*/
|
||||
#define TRACE_BUFFER_HEADER_SPECIAL 0x45435254
|
||||
|
||||
#if KBASE_TRACE_ENABLE
|
||||
static const char *kbasep_trace_code_string[] = {
|
||||
/* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
|
||||
* THIS MUST BE USED AT THE START OF THE ARRAY */
|
||||
#define KBASE_TRACE_CODE_MAKE_CODE(X) # X
|
||||
#include "mali_kbase_trace_defs.h"
|
||||
#undef KBASE_TRACE_CODE_MAKE_CODE
|
||||
};
|
||||
#endif
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
//#define DEBUG_MESSAGE_SIZE 256
|
||||
#define DEBUG_MESSAGE_SIZE KBASE_TRACE_SIZE
|
||||
|
||||
static int kbasep_trace_init(struct kbase_device *kbdev);
|
||||
static void kbasep_trace_term(struct kbase_device *kbdev);
|
||||
static void kbasep_trace_hook_wrapper(void *param);
|
||||
|
||||
struct kbase_device *kbase_device_alloc(void)
|
||||
{
|
||||
return kzalloc(sizeof(struct kbase_device), GFP_KERNEL);
|
||||
}
|
||||
|
||||
static int kbase_device_as_init(struct kbase_device *kbdev, int i)
|
||||
{
|
||||
const char format[] = "mali_mmu%d";
|
||||
char name[sizeof(format)];
|
||||
const char poke_format[] = "mali_mmu%d_poker";
|
||||
char poke_name[sizeof(poke_format)];
|
||||
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
|
||||
snprintf(poke_name, sizeof(poke_name), poke_format, i);
|
||||
|
||||
snprintf(name, sizeof(name), format, i);
|
||||
|
||||
kbdev->as[i].number = i;
|
||||
kbdev->as[i].fault_addr = 0ULL;
|
||||
|
||||
kbdev->as[i].pf_wq = alloc_workqueue(name, 0, 1);
|
||||
if (!kbdev->as[i].pf_wq)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_init(&kbdev->as[i].transaction_mutex);
|
||||
INIT_WORK(&kbdev->as[i].work_pagefault, page_fault_worker);
|
||||
INIT_WORK(&kbdev->as[i].work_busfault, bus_fault_worker);
|
||||
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316)) {
|
||||
struct hrtimer *poke_timer = &kbdev->as[i].poke_timer;
|
||||
struct work_struct *poke_work = &kbdev->as[i].poke_work;
|
||||
|
||||
kbdev->as[i].poke_wq = alloc_workqueue(poke_name, 0, 1);
|
||||
if (!kbdev->as[i].poke_wq) {
|
||||
destroy_workqueue(kbdev->as[i].pf_wq);
|
||||
return -EINVAL;
|
||||
}
|
||||
KBASE_DEBUG_ASSERT(!object_is_on_stack(poke_work));
|
||||
INIT_WORK(poke_work, kbasep_as_do_poke);
|
||||
|
||||
hrtimer_init(poke_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
|
||||
poke_timer->function = kbasep_as_poke_timer_callback;
|
||||
|
||||
kbdev->as[i].poke_refcount = 0;
|
||||
kbdev->as[i].poke_state = 0u;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbase_device_as_term(struct kbase_device *kbdev, int i)
|
||||
{
|
||||
destroy_workqueue(kbdev->as[i].pf_wq);
|
||||
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_8316))
|
||||
destroy_workqueue(kbdev->as[i].poke_wq);
|
||||
}
|
||||
|
||||
static int kbase_device_all_as_init(struct kbase_device *kbdev)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < kbdev->nr_hw_address_spaces; i++) {
|
||||
err = kbase_device_as_init(kbdev, i);
|
||||
if (err)
|
||||
goto free_workqs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
free_workqs:
|
||||
for (; i > 0; i--)
|
||||
kbase_device_as_term(kbdev, i);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void kbase_device_all_as_term(struct kbase_device *kbdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kbdev->nr_hw_address_spaces; i++)
|
||||
kbase_device_as_term(kbdev, i);
|
||||
}
|
||||
|
||||
int kbase_device_init(struct kbase_device * const kbdev)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
spin_lock_init(&kbdev->mmu_mask_change);
|
||||
/* Get the list of workarounds for issues on the current HW
|
||||
* (identified by the GPU_ID register)
|
||||
*/
|
||||
err = kbase_hw_set_issues_mask(kbdev);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
/* Set the list of features available on the current HW
|
||||
* (identified by the GPU_ID register)
|
||||
*/
|
||||
kbase_hw_set_features_mask(kbdev);
|
||||
|
||||
/* On Linux 4.0+, dma coherency is determined from device tree */
|
||||
#if defined(CONFIG_ARM64) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
|
||||
set_dma_ops(kbdev->dev, &noncoherent_swiotlb_dma_ops);
|
||||
#endif
|
||||
|
||||
/* Workaround a pre-3.13 Linux issue, where dma_mask is NULL when our
|
||||
* device structure was created by device-tree
|
||||
*/
|
||||
if (!kbdev->dev->dma_mask)
|
||||
kbdev->dev->dma_mask = &kbdev->dev->coherent_dma_mask;
|
||||
|
||||
err = dma_set_mask(kbdev->dev,
|
||||
DMA_BIT_MASK(kbdev->gpu_props.mmu.pa_bits));
|
||||
if (err)
|
||||
goto dma_set_mask_failed;
|
||||
|
||||
err = dma_set_coherent_mask(kbdev->dev,
|
||||
DMA_BIT_MASK(kbdev->gpu_props.mmu.pa_bits));
|
||||
if (err)
|
||||
goto dma_set_mask_failed;
|
||||
|
||||
kbdev->nr_hw_address_spaces = kbdev->gpu_props.num_address_spaces;
|
||||
|
||||
err = kbase_device_all_as_init(kbdev);
|
||||
if (err)
|
||||
goto as_init_failed;
|
||||
|
||||
spin_lock_init(&kbdev->hwcnt.lock);
|
||||
|
||||
err = kbasep_trace_init(kbdev);
|
||||
if (err)
|
||||
goto term_as;
|
||||
|
||||
mutex_init(&kbdev->cacheclean_lock);
|
||||
|
||||
#ifdef CONFIG_MALI_TRACE_TIMELINE
|
||||
for (i = 0; i < BASE_JM_MAX_NR_SLOTS; ++i)
|
||||
kbdev->timeline.slot_atoms_submitted[i] = 0;
|
||||
|
||||
for (i = 0; i <= KBASEP_TIMELINE_PM_EVENT_LAST; ++i)
|
||||
atomic_set(&kbdev->timeline.pm_event_uid[i], 0);
|
||||
#endif /* CONFIG_MALI_TRACE_TIMELINE */
|
||||
|
||||
/* fbdump profiling controls set to 0 - fbdump not enabled until changed by gator */
|
||||
for (i = 0; i < FBDUMP_CONTROL_MAX; i++)
|
||||
kbdev->kbase_profiling_controls[i] = 0;
|
||||
|
||||
kbase_debug_assert_register_hook(&kbasep_trace_hook_wrapper, kbdev);
|
||||
|
||||
atomic_set(&kbdev->ctx_num, 0);
|
||||
|
||||
err = kbase_instr_backend_init(kbdev);
|
||||
if (err)
|
||||
goto term_trace;
|
||||
|
||||
kbdev->pm.dvfs_period = DEFAULT_PM_DVFS_PERIOD;
|
||||
|
||||
kbdev->reset_timeout_ms = DEFAULT_RESET_TIMEOUT_MS;
|
||||
|
||||
kbdev->mmu_mode = kbase_mmu_mode_get_lpae();
|
||||
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
init_waitqueue_head(&kbdev->driver_inactive_wait);
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
|
||||
return 0;
|
||||
term_trace:
|
||||
kbasep_trace_term(kbdev);
|
||||
term_as:
|
||||
kbase_device_all_as_term(kbdev);
|
||||
as_init_failed:
|
||||
dma_set_mask_failed:
|
||||
fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
void kbase_device_term(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev);
|
||||
|
||||
#if KBASE_TRACE_ENABLE
|
||||
kbase_debug_assert_register_hook(NULL, NULL);
|
||||
#endif
|
||||
|
||||
kbase_instr_backend_term(kbdev);
|
||||
|
||||
kbasep_trace_term(kbdev);
|
||||
|
||||
kbase_device_all_as_term(kbdev);
|
||||
}
|
||||
|
||||
void kbase_device_free(struct kbase_device *kbdev)
|
||||
{
|
||||
kfree(kbdev);
|
||||
}
|
||||
|
||||
void kbase_device_trace_buffer_install(struct kbase_context *kctx, u32 *tb, size_t size)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kctx);
|
||||
KBASE_DEBUG_ASSERT(tb);
|
||||
|
||||
/* set up the header */
|
||||
/* magic number in the first 4 bytes */
|
||||
tb[0] = TRACE_BUFFER_HEADER_SPECIAL;
|
||||
/* Store (write offset = 0, wrap counter = 0, transaction active = no)
|
||||
* write offset 0 means never written.
|
||||
* Offsets 1 to (wrap_offset - 1) used to store values when trace started
|
||||
*/
|
||||
tb[1] = 0;
|
||||
|
||||
/* install trace buffer */
|
||||
spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
|
||||
kctx->jctx.tb_wrap_offset = size / 8;
|
||||
kctx->jctx.tb = tb;
|
||||
spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
|
||||
}
|
||||
|
||||
void kbase_device_trace_buffer_uninstall(struct kbase_context *kctx)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kctx);
|
||||
spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
|
||||
kctx->jctx.tb = NULL;
|
||||
kctx->jctx.tb_wrap_offset = 0;
|
||||
spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
|
||||
}
|
||||
|
||||
void kbase_device_trace_register_access(struct kbase_context *kctx, enum kbase_reg_access_type type, u16 reg_offset, u32 reg_value)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kctx->jctx.tb_lock, flags);
|
||||
if (kctx->jctx.tb) {
|
||||
u16 wrap_count;
|
||||
u16 write_offset;
|
||||
u32 *tb = kctx->jctx.tb;
|
||||
u32 header_word;
|
||||
|
||||
header_word = tb[1];
|
||||
KBASE_DEBUG_ASSERT(0 == (header_word & 0x1));
|
||||
|
||||
wrap_count = (header_word >> 1) & 0x7FFF;
|
||||
write_offset = (header_word >> 16) & 0xFFFF;
|
||||
|
||||
/* mark as transaction in progress */
|
||||
tb[1] |= 0x1;
|
||||
mb();
|
||||
|
||||
/* calculate new offset */
|
||||
write_offset++;
|
||||
if (write_offset == kctx->jctx.tb_wrap_offset) {
|
||||
/* wrap */
|
||||
write_offset = 1;
|
||||
wrap_count++;
|
||||
wrap_count &= 0x7FFF; /* 15bit wrap counter */
|
||||
}
|
||||
|
||||
/* store the trace entry at the selected offset */
|
||||
tb[write_offset * 2 + 0] = (reg_offset & ~0x3) | ((type == REG_WRITE) ? 0x1 : 0x0);
|
||||
tb[write_offset * 2 + 1] = reg_value;
|
||||
mb();
|
||||
|
||||
/* new header word */
|
||||
header_word = (write_offset << 16) | (wrap_count << 1) | 0x0; /* transaction complete */
|
||||
tb[1] = header_word;
|
||||
}
|
||||
spin_unlock_irqrestore(&kctx->jctx.tb_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Device trace functions
|
||||
*/
|
||||
#if KBASE_TRACE_ENABLE
|
||||
|
||||
static int kbasep_trace_init(struct kbase_device *kbdev)
|
||||
{
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifndef CONFIG_MALI_EXYNOS_TRACE
|
||||
struct kbase_trace *rbuf;
|
||||
|
||||
rbuf = kmalloc_array(KBASE_TRACE_SIZE, sizeof(*rbuf), GFP_KERNEL);
|
||||
|
||||
if (!rbuf)
|
||||
return -EINVAL;
|
||||
|
||||
kbdev->trace_rbuf = rbuf;
|
||||
spin_lock_init(&kbdev->trace_lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbasep_trace_term(struct kbase_device *kbdev)
|
||||
{
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifndef CONFIG_MALI_EXYNOS_TRACE
|
||||
kfree(kbdev->trace_rbuf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
//static
|
||||
void kbasep_trace_format_msg(struct kbase_trace *trace_msg, char *buffer, int len)
|
||||
{
|
||||
s32 written = 0;
|
||||
|
||||
/* Initial part of message */
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d.%.6d,%d,%d,%s,%p,", (int)trace_msg->timestamp.tv_sec, (int)(trace_msg->timestamp.tv_nsec / 1000), trace_msg->thread_id, trace_msg->cpu, kbasep_trace_code_string[trace_msg->code], trace_msg->ctx), 0);
|
||||
|
||||
if (trace_msg->katom)
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), "atom %d (ud: 0x%llx 0x%llx)", trace_msg->atom_number, trace_msg->atom_udata[0], trace_msg->atom_udata[1]), 0);
|
||||
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), ",%.8llx,", trace_msg->gpu_addr), 0);
|
||||
|
||||
/* NOTE: Could add function callbacks to handle different message types */
|
||||
/* Jobslot present */
|
||||
if (trace_msg->flags & KBASE_TRACE_FLAG_JOBSLOT)
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d", trace_msg->jobslot), 0);
|
||||
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), ","), 0);
|
||||
|
||||
/* Refcount present */
|
||||
if (trace_msg->flags & KBASE_TRACE_FLAG_REFCOUNT)
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), "%d", trace_msg->refcount), 0);
|
||||
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), ","), 0);
|
||||
|
||||
/* Rest of message */
|
||||
written += MAX(snprintf(buffer + written, MAX(len - written, 0), "0x%.8lx", trace_msg->info_val), 0);
|
||||
}
|
||||
|
||||
static void kbasep_trace_dump_msg(struct kbase_device *kbdev, struct kbase_trace *trace_msg)
|
||||
{
|
||||
char buffer[DEBUG_MESSAGE_SIZE];
|
||||
|
||||
kbasep_trace_format_msg(trace_msg, buffer, DEBUG_MESSAGE_SIZE);
|
||||
dev_dbg(kbdev->dev, "%s", buffer);
|
||||
}
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifdef CONFIG_MALI_EXYNOS_TRACE
|
||||
bool check_trace_code(enum kbase_trace_code code)
|
||||
{
|
||||
unsigned int temp = code;
|
||||
|
||||
switch(temp) {
|
||||
case KBASE_TRACE_CODE(CORE_CTX_DESTROY):
|
||||
case KBASE_TRACE_CODE(CORE_GPU_SOFT_RESET):
|
||||
case KBASE_TRACE_CODE(CORE_GPU_HARD_RESET):
|
||||
case KBASE_TRACE_CODE(JM_SOFTSTOP):
|
||||
case KBASE_TRACE_CODE(JM_HARDSTOP):
|
||||
case KBASE_TRACE_CODE(LSI_GPU_ON):
|
||||
case KBASE_TRACE_CODE(LSI_GPU_OFF):
|
||||
case KBASE_TRACE_CODE(LSI_SUSPEND):
|
||||
case KBASE_TRACE_CODE(LSI_RESUME):
|
||||
case KBASE_TRACE_CODE(LSI_CLOCK_VALUE):
|
||||
case KBASE_TRACE_CODE(LSI_TMU_VALUE):
|
||||
case KBASE_TRACE_CODE(LSI_VOL_VALUE):
|
||||
case KBASE_TRACE_CODE(LSI_REGISTER_DUMP):
|
||||
case KBASE_TRACE_CODE(LSI_CLOCK_ON):
|
||||
case KBASE_TRACE_CODE(LSI_CLOCK_OFF):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_ON_DVFS):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_OFF_DVFS):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_ON_GPR):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_OFF_GPR):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_BT_ON):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_BT_OFF):
|
||||
case KBASE_TRACE_CODE(LSI_HWCNT_VSYNC_SKIP):
|
||||
case KBASE_TRACE_CODE(LSI_CHECKSUM):
|
||||
case KBASE_TRACE_CODE(LSI_GPU_MAX_LOCK):
|
||||
case KBASE_TRACE_CODE(LSI_GPU_MIN_LOCK):
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void kbasep_trace_add(struct kbase_device *kbdev, enum kbase_trace_code code, void *ctx, struct kbase_jd_atom *katom, u64 gpu_addr, u8 flags, int refcount, int jobslot, unsigned long info_val)
|
||||
{
|
||||
unsigned long irqflags;
|
||||
struct kbase_trace *trace_msg;
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifdef CONFIG_MALI_EXYNOS_TRACE
|
||||
u64 time;
|
||||
unsigned long rem_nsec;
|
||||
|
||||
if (!check_trace_code(code))
|
||||
return;
|
||||
|
||||
if (code == KBASE_TRACE_CODE(JM_SOFTSTOP) || code == KBASE_TRACE_CODE(JM_HARDSTOP)) {
|
||||
if (gpu_is_power_on())
|
||||
gpu_dump_register_hooks(kbdev);
|
||||
else
|
||||
dev_err(kbdev->dev, "GPU raized JM_SOFTSTOP or JM_HARDSTOP. but GPU power is down. Skip the GPU dump\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&kbdev->trace_lock, irqflags);
|
||||
|
||||
trace_msg = &kbdev->trace_rbuf[kbdev->trace_next_in];
|
||||
|
||||
/* Fill the message */
|
||||
trace_msg->thread_id = task_pid_nr(current);
|
||||
trace_msg->cpu = task_cpu(current);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifdef CONFIG_MALI_EXYNOS_TRACE
|
||||
time = local_clock();
|
||||
rem_nsec = do_div(time, 1000000000);
|
||||
trace_msg->timestamp.tv_sec = time;
|
||||
trace_msg->timestamp.tv_nsec = rem_nsec;
|
||||
#else
|
||||
getnstimeofday(&trace_msg->timestamp);
|
||||
#endif
|
||||
|
||||
trace_msg->code = code;
|
||||
trace_msg->ctx = ctx;
|
||||
|
||||
if (NULL == katom) {
|
||||
trace_msg->katom = false;
|
||||
} else {
|
||||
trace_msg->katom = true;
|
||||
trace_msg->atom_number = kbase_jd_atom_id(katom->kctx, katom);
|
||||
trace_msg->atom_udata[0] = katom->udata.blob[0];
|
||||
trace_msg->atom_udata[1] = katom->udata.blob[1];
|
||||
}
|
||||
|
||||
trace_msg->gpu_addr = gpu_addr;
|
||||
trace_msg->jobslot = jobslot;
|
||||
trace_msg->refcount = MIN((unsigned int)refcount, 0xFF);
|
||||
trace_msg->info_val = info_val;
|
||||
trace_msg->flags = flags;
|
||||
|
||||
/* Update the ringbuffer indices */
|
||||
kbdev->trace_next_in = (kbdev->trace_next_in + 1) & KBASE_TRACE_MASK;
|
||||
if (kbdev->trace_next_in == kbdev->trace_first_out)
|
||||
kbdev->trace_first_out = (kbdev->trace_first_out + 1) & KBASE_TRACE_MASK;
|
||||
|
||||
/* Done */
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->trace_lock, irqflags);
|
||||
}
|
||||
|
||||
void kbasep_trace_clear(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&kbdev->trace_lock, flags);
|
||||
kbdev->trace_first_out = kbdev->trace_next_in;
|
||||
spin_unlock_irqrestore(&kbdev->trace_lock, flags);
|
||||
}
|
||||
|
||||
void kbasep_trace_dump(struct kbase_device *kbdev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 start;
|
||||
u32 end;
|
||||
|
||||
dev_dbg(kbdev->dev, "Dumping trace:\nsecs,nthread,cpu,code,ctx,katom,gpu_addr,jobslot,refcount,info_val");
|
||||
spin_lock_irqsave(&kbdev->trace_lock, flags);
|
||||
start = kbdev->trace_first_out;
|
||||
end = kbdev->trace_next_in;
|
||||
|
||||
while (start != end) {
|
||||
struct kbase_trace *trace_msg = &kbdev->trace_rbuf[start];
|
||||
|
||||
kbasep_trace_dump_msg(kbdev, trace_msg);
|
||||
|
||||
start = (start + 1) & KBASE_TRACE_MASK;
|
||||
}
|
||||
dev_dbg(kbdev->dev, "TRACE_END");
|
||||
|
||||
spin_unlock_irqrestore(&kbdev->trace_lock, flags);
|
||||
|
||||
KBASE_TRACE_CLEAR(kbdev);
|
||||
}
|
||||
|
||||
static void kbasep_trace_hook_wrapper(void *param)
|
||||
{
|
||||
struct kbase_device *kbdev = (struct kbase_device *)param;
|
||||
|
||||
kbasep_trace_dump(kbdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct trace_seq_state {
|
||||
struct kbase_trace trace_buf[KBASE_TRACE_SIZE];
|
||||
u32 start;
|
||||
u32 end;
|
||||
};
|
||||
|
||||
static void *kbasep_trace_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
struct trace_seq_state *state = s->private;
|
||||
int i;
|
||||
|
||||
if (*pos > KBASE_TRACE_SIZE)
|
||||
return NULL;
|
||||
i = state->start + *pos;
|
||||
if ((state->end >= state->start && i >= state->end) ||
|
||||
i >= state->end + KBASE_TRACE_SIZE)
|
||||
return NULL;
|
||||
|
||||
i &= KBASE_TRACE_MASK;
|
||||
|
||||
return &state->trace_buf[i];
|
||||
}
|
||||
|
||||
static void kbasep_trace_seq_stop(struct seq_file *s, void *data)
|
||||
{
|
||||
}
|
||||
|
||||
static void *kbasep_trace_seq_next(struct seq_file *s, void *data, loff_t *pos)
|
||||
{
|
||||
struct trace_seq_state *state = s->private;
|
||||
int i;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
i = (state->start + *pos) & KBASE_TRACE_MASK;
|
||||
if (i == state->end)
|
||||
return NULL;
|
||||
|
||||
return &state->trace_buf[i];
|
||||
}
|
||||
|
||||
static int kbasep_trace_seq_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct kbase_trace *trace_msg = data;
|
||||
char buffer[DEBUG_MESSAGE_SIZE];
|
||||
|
||||
kbasep_trace_format_msg(trace_msg, buffer, DEBUG_MESSAGE_SIZE);
|
||||
seq_printf(s, "%s\n", buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct seq_operations kbasep_trace_seq_ops = {
|
||||
.start = kbasep_trace_seq_start,
|
||||
.next = kbasep_trace_seq_next,
|
||||
.stop = kbasep_trace_seq_stop,
|
||||
.show = kbasep_trace_seq_show,
|
||||
};
|
||||
|
||||
static int kbasep_trace_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct kbase_device *kbdev = inode->i_private;
|
||||
unsigned long flags;
|
||||
|
||||
struct trace_seq_state *state;
|
||||
|
||||
state = __seq_open_private(file, &kbasep_trace_seq_ops, sizeof(*state));
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_irqsave(&kbdev->trace_lock, flags);
|
||||
state->start = kbdev->trace_first_out;
|
||||
state->end = kbdev->trace_next_in;
|
||||
memcpy(state->trace_buf, kbdev->trace_rbuf, sizeof(state->trace_buf));
|
||||
spin_unlock_irqrestore(&kbdev->trace_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
//static
|
||||
const struct file_operations kbasep_trace_debugfs_fops = {
|
||||
.open = kbasep_trace_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
void kbasep_trace_debugfs_init(struct kbase_device *kbdev)
|
||||
{
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
#ifndef CONFIG_MALI_EXYNOS_TRACE
|
||||
debugfs_create_file("mali_trace", S_IRUGO,
|
||||
kbdev->mali_debugfs_directory, kbdev,
|
||||
&kbasep_trace_debugfs_fops);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
void kbasep_trace_debugfs_init(struct kbase_device *kbdev)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
#else /* KBASE_TRACE_ENABLE */
|
||||
static int kbasep_trace_init(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbasep_trace_term(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
|
||||
static void kbasep_trace_hook_wrapper(void *param)
|
||||
{
|
||||
CSTD_UNUSED(param);
|
||||
}
|
||||
|
||||
void kbasep_trace_dump(struct kbase_device *kbdev)
|
||||
{
|
||||
CSTD_UNUSED(kbdev);
|
||||
}
|
||||
#endif /* KBASE_TRACE_ENABLE */
|
||||
|
||||
void kbase_set_profiling_control(struct kbase_device *kbdev, u32 control, u32 value)
|
||||
{
|
||||
switch (control) {
|
||||
case FBDUMP_CONTROL_ENABLE:
|
||||
/* fall through */
|
||||
case FBDUMP_CONTROL_RATE:
|
||||
/* fall through */
|
||||
case SW_COUNTER_ENABLE:
|
||||
/* fall through */
|
||||
case FBDUMP_CONTROL_RESIZE_FACTOR:
|
||||
kbdev->kbase_profiling_controls[control] = value;
|
||||
break;
|
||||
default:
|
||||
dev_err(kbdev->dev, "Profiling control %d not found\n", control);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 kbase_get_profiling_control(struct kbase_device *kbdev, u32 control)
|
||||
{
|
||||
u32 ret_value = 0;
|
||||
|
||||
switch (control) {
|
||||
case FBDUMP_CONTROL_ENABLE:
|
||||
/* fall through */
|
||||
case FBDUMP_CONTROL_RATE:
|
||||
/* fall through */
|
||||
case SW_COUNTER_ENABLE:
|
||||
/* fall through */
|
||||
case FBDUMP_CONTROL_RESIZE_FACTOR:
|
||||
ret_value = kbdev->kbase_profiling_controls[control];
|
||||
break;
|
||||
default:
|
||||
dev_err(kbdev->dev, "Profiling control %d not found\n", control);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by gator to control the production of
|
||||
* profiling information at runtime
|
||||
* */
|
||||
|
||||
void _mali_profiling_control(u32 action, u32 value)
|
||||
{
|
||||
struct kbase_device *kbdev = NULL;
|
||||
|
||||
/* find the first i.e. call with -1 */
|
||||
kbdev = kbase_find_device(-1);
|
||||
|
||||
if (NULL != kbdev)
|
||||
kbase_set_profiling_control(kbdev, action, value);
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(_mali_profiling_control);
|
||||
|
||||
76
drivers/gpu/arm/t72x/r7p0/mali_kbase_disjoint_events.c
Normal file
76
drivers/gpu/arm/t72x/r7p0/mali_kbase_disjoint_events.c
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel disjoint events helper functions
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
|
||||
void kbase_disjoint_init(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
atomic_set(&kbdev->disjoint_event.count, 0);
|
||||
atomic_set(&kbdev->disjoint_event.state, 0);
|
||||
}
|
||||
|
||||
/* increment the disjoint event count */
|
||||
void kbase_disjoint_event(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
atomic_inc(&kbdev->disjoint_event.count);
|
||||
}
|
||||
|
||||
/* increment the state and the event counter */
|
||||
void kbase_disjoint_state_up(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
atomic_inc(&kbdev->disjoint_event.state);
|
||||
|
||||
kbase_disjoint_event(kbdev);
|
||||
}
|
||||
|
||||
/* decrement the state */
|
||||
void kbase_disjoint_state_down(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
KBASE_DEBUG_ASSERT(atomic_read(&kbdev->disjoint_event.state) > 0);
|
||||
|
||||
kbase_disjoint_event(kbdev);
|
||||
|
||||
atomic_dec(&kbdev->disjoint_event.state);
|
||||
}
|
||||
|
||||
/* increments the count only if the state is > 0 */
|
||||
void kbase_disjoint_event_potential(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
if (atomic_read(&kbdev->disjoint_event.state))
|
||||
kbase_disjoint_event(kbdev);
|
||||
}
|
||||
|
||||
u32 kbase_disjoint_event_get(struct kbase_device *kbdev)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kbdev != NULL);
|
||||
|
||||
return atomic_read(&kbdev->disjoint_event.count);
|
||||
}
|
||||
KBASE_EXPORT_TEST_API(kbase_disjoint_event_get);
|
||||
272
drivers/gpu/arm/t72x/r7p0/mali_kbase_event.c
Normal file
272
drivers/gpu/arm/t72x/r7p0/mali_kbase_event.c
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h>
|
||||
#include <mali_kbase_debug.h>
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
#include <lockdep.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MALI_MIPE_ENABLED)
|
||||
#include <mali_kbase_tlstream.h>
|
||||
#endif
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
static bool kbase_event_check_error(struct kbase_context *kctx, struct kbase_jd_atom *katom, base_jd_udata *data)
|
||||
{
|
||||
pgd_t *pgd;
|
||||
struct mm_struct *mm;
|
||||
|
||||
memset(data->blob, 0, sizeof(data->blob));
|
||||
|
||||
if (!kctx || !katom) {
|
||||
printk("kctx: 0x%p, katom: 0x%p\n", kctx, katom);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (katom->status != KBASE_JD_ATOM_STATE_COMPLETED) {
|
||||
printk("Abnormal situation\n");
|
||||
printk("kctx: 0x%p, katom: 0x%p, katom->status: 0x%x\n", kctx, katom, katom->status);
|
||||
return false;
|
||||
}
|
||||
|
||||
mm = katom->kctx->process_mm;
|
||||
pgd = pgd_offset(mm, (unsigned long)&katom->completed);
|
||||
if (pgd_none(*pgd) || pgd_bad(*pgd)) {
|
||||
printk("Abnormal katom\n");
|
||||
printk("katom->kctx: 0x%p, katom->kctx->tgid: %d, katom->kctx->process_mm: 0x%p, pgd: 0x%px\n", katom->kctx, katom->kctx->tgid, katom->kctx->process_mm, pgd);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
if (katom->completed.lock.dep_map.key) {
|
||||
pgd = pgd_offset(mm, (unsigned long)&katom->completed.lock.dep_map.key);
|
||||
if (pgd_none(*pgd) || pgd_bad(*pgd)) {
|
||||
printk("Abnormal katom 2\n");
|
||||
printk("katom->kctx: 0x%p, katom->kctx->tgid: %d, katom->kctx->process_mm: 0x%p, pgd: 0x%px\n", katom->kctx, katom->kctx->tgid, katom->kctx->process_mm, pgd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct base_jd_udata kbase_event_process(struct kbase_context *kctx, struct kbase_jd_atom *katom)
|
||||
{
|
||||
struct base_jd_udata data;
|
||||
|
||||
lockdep_assert_held(&kctx->jctx.lock);
|
||||
|
||||
KBASE_DEBUG_ASSERT(kctx != NULL);
|
||||
KBASE_DEBUG_ASSERT(katom != NULL);
|
||||
KBASE_DEBUG_ASSERT(katom->status == KBASE_JD_ATOM_STATE_COMPLETED);
|
||||
|
||||
/* MALI_SEC_INTEGRATION */
|
||||
if(kbase_event_check_error(kctx, katom, &data) == false)
|
||||
return data;
|
||||
|
||||
data = katom->udata;
|
||||
|
||||
KBASE_TIMELINE_ATOMS_IN_FLIGHT(kctx, atomic_sub_return(1, &kctx->timeline.jd_atoms_in_flight));
|
||||
|
||||
#if defined(CONFIG_MALI_MIPE_ENABLED)
|
||||
kbase_tlstream_tl_nret_atom_ctx(katom, kctx);
|
||||
kbase_tlstream_tl_del_atom(katom);
|
||||
#endif
|
||||
|
||||
katom->status = KBASE_JD_ATOM_STATE_UNUSED;
|
||||
|
||||
wake_up(&katom->completed);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int kbase_event_pending(struct kbase_context *ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
KBASE_DEBUG_ASSERT(ctx);
|
||||
|
||||
mutex_lock(&ctx->event_mutex);
|
||||
ret = (!list_empty(&ctx->event_list)) || (true == ctx->event_closed);
|
||||
mutex_unlock(&ctx->event_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_event_pending);
|
||||
|
||||
int kbase_event_dequeue(struct kbase_context *ctx, struct base_jd_event_v2 *uevent)
|
||||
{
|
||||
struct kbase_jd_atom *atom;
|
||||
|
||||
KBASE_DEBUG_ASSERT(ctx);
|
||||
|
||||
mutex_lock(&ctx->event_mutex);
|
||||
|
||||
if (list_empty(&ctx->event_list)) {
|
||||
if (!ctx->event_closed) {
|
||||
mutex_unlock(&ctx->event_mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* generate the BASE_JD_EVENT_DRV_TERMINATED message on the fly */
|
||||
mutex_unlock(&ctx->event_mutex);
|
||||
uevent->event_code = BASE_JD_EVENT_DRV_TERMINATED;
|
||||
memset(&uevent->udata, 0, sizeof(uevent->udata));
|
||||
dev_dbg(ctx->kbdev->dev,
|
||||
"event system closed, returning BASE_JD_EVENT_DRV_TERMINATED(0x%X)\n",
|
||||
BASE_JD_EVENT_DRV_TERMINATED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* normal event processing */
|
||||
atom = list_entry(ctx->event_list.next, struct kbase_jd_atom, dep_item[0]);
|
||||
list_del(ctx->event_list.next);
|
||||
|
||||
mutex_unlock(&ctx->event_mutex);
|
||||
|
||||
dev_dbg(ctx->kbdev->dev, "event dequeuing %p\n", (void *)atom);
|
||||
uevent->event_code = atom->event_code;
|
||||
uevent->atom_number = (atom - ctx->jctx.atoms);
|
||||
|
||||
if (atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)
|
||||
kbase_jd_free_external_resources(atom);
|
||||
|
||||
mutex_lock(&ctx->jctx.lock);
|
||||
uevent->udata = kbase_event_process(ctx, atom);
|
||||
mutex_unlock(&ctx->jctx.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_event_dequeue);
|
||||
|
||||
/**
|
||||
* kbase_event_process_noreport_worker - Worker for processing atoms that do not
|
||||
* return an event but do have external
|
||||
* resources
|
||||
* @data: Work structure
|
||||
*/
|
||||
static void kbase_event_process_noreport_worker(struct work_struct *data)
|
||||
{
|
||||
struct kbase_jd_atom *katom = container_of(data, struct kbase_jd_atom,
|
||||
work);
|
||||
struct kbase_context *kctx = katom->kctx;
|
||||
|
||||
if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)
|
||||
kbase_jd_free_external_resources(katom);
|
||||
|
||||
mutex_lock(&kctx->jctx.lock);
|
||||
kbase_event_process(kctx, katom);
|
||||
mutex_unlock(&kctx->jctx.lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_event_process_noreport - Process atoms that do not return an event
|
||||
* @kctx: Context pointer
|
||||
* @katom: Atom to be processed
|
||||
*
|
||||
* Atoms that do not have external resources will be processed immediately.
|
||||
* Atoms that do have external resources will be processed on a workqueue, in
|
||||
* order to avoid locking issues.
|
||||
*/
|
||||
static void kbase_event_process_noreport(struct kbase_context *kctx,
|
||||
struct kbase_jd_atom *katom)
|
||||
{
|
||||
if (katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) {
|
||||
INIT_WORK(&katom->work, kbase_event_process_noreport_worker);
|
||||
queue_work(kctx->event_workq, &katom->work);
|
||||
} else {
|
||||
kbase_event_process(kctx, katom);
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *atom)
|
||||
{
|
||||
if (atom->core_req & BASE_JD_REQ_EVENT_ONLY_ON_FAILURE) {
|
||||
if (atom->event_code == BASE_JD_EVENT_DONE) {
|
||||
/* Don't report the event */
|
||||
kbase_event_process_noreport(ctx, atom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (atom->core_req & BASEP_JD_REQ_EVENT_NEVER) {
|
||||
/* Don't report the event */
|
||||
kbase_event_process_noreport(ctx, atom);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&ctx->event_mutex);
|
||||
list_add_tail(&atom->dep_item[0], &ctx->event_list);
|
||||
mutex_unlock(&ctx->event_mutex);
|
||||
|
||||
kbase_event_wakeup(ctx);
|
||||
}
|
||||
KBASE_EXPORT_TEST_API(kbase_event_post);
|
||||
|
||||
void kbase_event_close(struct kbase_context *kctx)
|
||||
{
|
||||
mutex_lock(&kctx->event_mutex);
|
||||
kctx->event_closed = true;
|
||||
mutex_unlock(&kctx->event_mutex);
|
||||
kbase_event_wakeup(kctx);
|
||||
}
|
||||
|
||||
int kbase_event_init(struct kbase_context *kctx)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kctx);
|
||||
|
||||
INIT_LIST_HEAD(&kctx->event_list);
|
||||
mutex_init(&kctx->event_mutex);
|
||||
kctx->event_closed = false;
|
||||
kctx->event_workq = alloc_workqueue("kbase_event", WQ_MEM_RECLAIM, 1);
|
||||
|
||||
if (NULL == kctx->event_workq)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_event_init);
|
||||
|
||||
void kbase_event_cleanup(struct kbase_context *kctx)
|
||||
{
|
||||
KBASE_DEBUG_ASSERT(kctx);
|
||||
KBASE_DEBUG_ASSERT(kctx->event_workq);
|
||||
|
||||
flush_workqueue(kctx->event_workq);
|
||||
destroy_workqueue(kctx->event_workq);
|
||||
|
||||
/* We use kbase_event_dequeue to remove the remaining events as that
|
||||
* deals with all the cleanup needed for the atoms.
|
||||
*
|
||||
* Note: use of kctx->event_list without a lock is safe because this must be the last
|
||||
* thread using it (because we're about to terminate the lock)
|
||||
*/
|
||||
while (!list_empty(&kctx->event_list)) {
|
||||
struct base_jd_event_v2 event;
|
||||
|
||||
kbase_event_dequeue(kctx, &event);
|
||||
}
|
||||
}
|
||||
|
||||
KBASE_EXPORT_TEST_API(kbase_event_cleanup);
|
||||
45
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator.h
Normal file
45
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* NB taken from gator */
|
||||
/*
|
||||
* List of possible actions to be controlled by DS-5 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.
|
||||
*/
|
||||
#ifndef _KBASE_GATOR_H_
|
||||
#define _KBASE_GATOR_H_
|
||||
|
||||
#ifdef CONFIG_MALI_GATOR_SUPPORT
|
||||
#define GATOR_MAKE_EVENT(type, number) (((type) << 24) | ((number) << 16))
|
||||
#define GATOR_JOB_SLOT_START 1
|
||||
#define GATOR_JOB_SLOT_STOP 2
|
||||
#define GATOR_JOB_SLOT_SOFT_STOPPED 3
|
||||
|
||||
void kbase_trace_mali_job_slots_event(u32 event, const struct kbase_context *kctx, u8 atom_id);
|
||||
void kbase_trace_mali_pm_status(u32 event, u64 value);
|
||||
void kbase_trace_mali_pm_power_off(u32 event, u64 value);
|
||||
void kbase_trace_mali_pm_power_on(u32 event, u64 value);
|
||||
void kbase_trace_mali_page_fault_insert_pages(int event, u32 value);
|
||||
void kbase_trace_mali_mmu_as_in_use(int event);
|
||||
void kbase_trace_mali_mmu_as_released(int event);
|
||||
void kbase_trace_mali_total_alloc_pages_change(long long int event);
|
||||
|
||||
#endif /* CONFIG_MALI_GATOR_SUPPORT */
|
||||
|
||||
#endif /* _KBASE_GATOR_H_ */
|
||||
322
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_api.c
Normal file
322
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_api.c
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase.h"
|
||||
#include "mali_kbase_hw.h"
|
||||
#include "mali_kbase_mem_linux.h"
|
||||
#include "mali_kbase_gator_api.h"
|
||||
#include "mali_kbase_gator_hwcnt_names.h"
|
||||
#include "mali_kbase_instr.h"
|
||||
|
||||
#define MALI_MAX_CORES_PER_GROUP 4
|
||||
#define MALI_MAX_NUM_BLOCKS_PER_GROUP 8
|
||||
#define MALI_COUNTERS_PER_BLOCK 64
|
||||
#define MALI_BYTES_PER_COUNTER 4
|
||||
|
||||
struct kbase_gator_hwcnt_handles {
|
||||
struct kbase_device *kbdev;
|
||||
struct kbase_context *kctx;
|
||||
u64 hwcnt_gpu_va;
|
||||
void *hwcnt_cpu_va;
|
||||
struct kbase_vmap_struct hwcnt_map;
|
||||
};
|
||||
|
||||
const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters)
|
||||
{
|
||||
uint32_t gpu_id;
|
||||
const char * const *hardware_counters;
|
||||
struct kbase_device *kbdev;
|
||||
|
||||
if (!total_counters)
|
||||
return NULL;
|
||||
|
||||
/* Get the first device - it doesn't matter in this case */
|
||||
kbdev = kbase_find_device(-1);
|
||||
if (!kbdev)
|
||||
return NULL;
|
||||
|
||||
gpu_id = kbdev->gpu_props.props.core_props.product_id;
|
||||
|
||||
switch (gpu_id) {
|
||||
/* If we are using a Mali-T60x device */
|
||||
case GPU_ID_PI_T60X:
|
||||
hardware_counters = hardware_counters_mali_t60x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t60x);
|
||||
break;
|
||||
/* If we are using a Mali-T62x device */
|
||||
case GPU_ID_PI_T62X:
|
||||
hardware_counters = hardware_counters_mali_t62x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t62x);
|
||||
break;
|
||||
/* If we are using a Mali-T72x device */
|
||||
case GPU_ID_PI_T72X:
|
||||
hardware_counters = hardware_counters_mali_t72x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t72x);
|
||||
break;
|
||||
/* If we are using a Mali-T76x device */
|
||||
case GPU_ID_PI_T76X:
|
||||
hardware_counters = hardware_counters_mali_t76x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t76x);
|
||||
break;
|
||||
/* If we are using a Mali-T82x device */
|
||||
case GPU_ID_PI_T82X:
|
||||
hardware_counters = hardware_counters_mali_t82x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t82x);
|
||||
break;
|
||||
/* If we are using a Mali-T83x device */
|
||||
case GPU_ID_PI_T83X:
|
||||
hardware_counters = hardware_counters_mali_t83x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t83x);
|
||||
break;
|
||||
/* If we are using a Mali-T86x device */
|
||||
case GPU_ID_PI_T86X:
|
||||
hardware_counters = hardware_counters_mali_t86x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t86x);
|
||||
break;
|
||||
/* If we are using a Mali-T88x device */
|
||||
case GPU_ID_PI_TFRX:
|
||||
hardware_counters = hardware_counters_mali_t88x;
|
||||
*total_counters = ARRAY_SIZE(hardware_counters_mali_t88x);
|
||||
break;
|
||||
default:
|
||||
hardware_counters = NULL;
|
||||
*total_counters = 0;
|
||||
dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n", gpu_id);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Release the kbdev reference. */
|
||||
kbase_release_device(kbdev);
|
||||
|
||||
/* If we return a string array take a reference on the module (or fail). */
|
||||
if (hardware_counters && !try_module_get(THIS_MODULE))
|
||||
return NULL;
|
||||
|
||||
return hardware_counters;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init_names);
|
||||
|
||||
void kbase_gator_hwcnt_term_names(void)
|
||||
{
|
||||
/* Release the module reference. */
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names);
|
||||
|
||||
struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info)
|
||||
{
|
||||
struct kbase_gator_hwcnt_handles *hand;
|
||||
struct kbase_uk_hwcnt_setup setup;
|
||||
int err;
|
||||
uint32_t dump_size = 0, i = 0;
|
||||
struct kbase_va_region *reg;
|
||||
u64 flags;
|
||||
u64 nr_pages;
|
||||
u16 va_alignment = 0;
|
||||
|
||||
if (!in_out_info)
|
||||
return NULL;
|
||||
|
||||
hand = kzalloc(sizeof(*hand), GFP_KERNEL);
|
||||
if (!hand)
|
||||
return NULL;
|
||||
|
||||
/* Get the first device */
|
||||
hand->kbdev = kbase_find_device(-1);
|
||||
if (!hand->kbdev)
|
||||
goto free_hand;
|
||||
|
||||
/* Create a kbase_context */
|
||||
hand->kctx = kbase_create_context(hand->kbdev, true);
|
||||
if (!hand->kctx)
|
||||
goto release_device;
|
||||
|
||||
in_out_info->nr_cores = hand->kbdev->gpu_props.num_cores;
|
||||
in_out_info->nr_core_groups = hand->kbdev->gpu_props.num_core_groups;
|
||||
in_out_info->gpu_id = hand->kbdev->gpu_props.props.core_props.product_id;
|
||||
|
||||
/* If we are using a v4 device (Mali-T6xx or Mali-T72x) */
|
||||
if (kbase_hw_has_feature(hand->kbdev, BASE_HW_FEATURE_V4)) {
|
||||
uint32_t cg, j;
|
||||
uint64_t core_mask;
|
||||
|
||||
/* There are 8 hardware counters blocks per core group */
|
||||
in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) *
|
||||
MALI_MAX_NUM_BLOCKS_PER_GROUP *
|
||||
in_out_info->nr_core_groups, GFP_KERNEL);
|
||||
|
||||
if (!in_out_info->hwc_layout)
|
||||
goto destroy_context;
|
||||
|
||||
dump_size = in_out_info->nr_core_groups *
|
||||
MALI_MAX_NUM_BLOCKS_PER_GROUP *
|
||||
MALI_COUNTERS_PER_BLOCK *
|
||||
MALI_BYTES_PER_COUNTER;
|
||||
|
||||
for (cg = 0; cg < in_out_info->nr_core_groups; cg++) {
|
||||
core_mask = hand->kbdev->gpu_props.props.coherency_info.group[cg].core_mask;
|
||||
|
||||
for (j = 0; j < MALI_MAX_CORES_PER_GROUP; j++) {
|
||||
if (core_mask & (1u << j))
|
||||
in_out_info->hwc_layout[i++] = SHADER_BLOCK;
|
||||
else
|
||||
in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
|
||||
}
|
||||
|
||||
in_out_info->hwc_layout[i++] = TILER_BLOCK;
|
||||
in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
|
||||
|
||||
in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
|
||||
|
||||
if (0 == cg)
|
||||
in_out_info->hwc_layout[i++] = JM_BLOCK;
|
||||
else
|
||||
in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
|
||||
}
|
||||
/* If we are using any other device */
|
||||
} else {
|
||||
uint32_t nr_l2, nr_sc, j;
|
||||
uint64_t core_mask;
|
||||
|
||||
nr_l2 = hand->kbdev->gpu_props.props.l2_props.num_l2_slices;
|
||||
|
||||
core_mask = hand->kbdev->gpu_props.props.coherency_info.group[0].core_mask;
|
||||
|
||||
nr_sc = hand->kbdev->gpu_props.props.coherency_info.group[0].num_cores;
|
||||
|
||||
/* The job manager and tiler sets of counters
|
||||
* are always present */
|
||||
in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * (2 + nr_sc + nr_l2), GFP_KERNEL);
|
||||
|
||||
if (!in_out_info->hwc_layout)
|
||||
goto destroy_context;
|
||||
|
||||
dump_size = (2 + nr_sc + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER;
|
||||
|
||||
in_out_info->hwc_layout[i++] = JM_BLOCK;
|
||||
in_out_info->hwc_layout[i++] = TILER_BLOCK;
|
||||
|
||||
for (j = 0; j < nr_l2; j++)
|
||||
in_out_info->hwc_layout[i++] = MMU_L2_BLOCK;
|
||||
|
||||
while (core_mask != 0ull) {
|
||||
if ((core_mask & 1ull) != 0ull)
|
||||
in_out_info->hwc_layout[i++] = SHADER_BLOCK;
|
||||
else
|
||||
in_out_info->hwc_layout[i++] = RESERVED_BLOCK;
|
||||
core_mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
in_out_info->nr_hwc_blocks = i;
|
||||
|
||||
in_out_info->size = dump_size;
|
||||
|
||||
flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_CPU_WR | BASE_MEM_PROT_GPU_WR;
|
||||
nr_pages = PFN_UP(dump_size);
|
||||
reg = kbase_mem_alloc(hand->kctx, nr_pages, nr_pages, 0,
|
||||
&flags, &hand->hwcnt_gpu_va, &va_alignment);
|
||||
if (!reg)
|
||||
goto free_layout;
|
||||
|
||||
hand->hwcnt_cpu_va = kbase_vmap(hand->kctx, hand->hwcnt_gpu_va,
|
||||
dump_size, &hand->hwcnt_map);
|
||||
|
||||
if (!hand->hwcnt_cpu_va)
|
||||
goto free_buffer;
|
||||
|
||||
in_out_info->kernel_dump_buffer = hand->hwcnt_cpu_va;
|
||||
memset(in_out_info->kernel_dump_buffer, 0, nr_pages * PAGE_SIZE);
|
||||
|
||||
/*setup.dump_buffer = (uintptr_t)in_out_info->kernel_dump_buffer;*/
|
||||
setup.dump_buffer = hand->hwcnt_gpu_va;
|
||||
setup.jm_bm = in_out_info->bitmask[0];
|
||||
setup.tiler_bm = in_out_info->bitmask[1];
|
||||
setup.shader_bm = in_out_info->bitmask[2];
|
||||
setup.mmu_l2_bm = in_out_info->bitmask[3];
|
||||
|
||||
err = kbase_instr_hwcnt_enable(hand->kctx, &setup);
|
||||
if (err)
|
||||
goto free_unmap;
|
||||
|
||||
kbase_instr_hwcnt_clear(hand->kctx);
|
||||
|
||||
return hand;
|
||||
|
||||
free_unmap:
|
||||
kbase_vunmap(hand->kctx, &hand->hwcnt_map);
|
||||
|
||||
free_buffer:
|
||||
kbase_mem_free(hand->kctx, hand->hwcnt_gpu_va);
|
||||
|
||||
free_layout:
|
||||
kfree(in_out_info->hwc_layout);
|
||||
|
||||
destroy_context:
|
||||
kbase_destroy_context(hand->kctx);
|
||||
|
||||
release_device:
|
||||
kbase_release_device(hand->kbdev);
|
||||
|
||||
free_hand:
|
||||
kfree(hand);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init);
|
||||
|
||||
void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles)
|
||||
{
|
||||
if (in_out_info)
|
||||
kfree(in_out_info->hwc_layout);
|
||||
|
||||
if (opaque_handles) {
|
||||
kbase_instr_hwcnt_disable(opaque_handles->kctx);
|
||||
kbase_vunmap(opaque_handles->kctx, &opaque_handles->hwcnt_map);
|
||||
kbase_mem_free(opaque_handles->kctx, opaque_handles->hwcnt_gpu_va);
|
||||
kbase_destroy_context(opaque_handles->kctx);
|
||||
kbase_release_device(opaque_handles->kbdev);
|
||||
kfree(opaque_handles);
|
||||
}
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term);
|
||||
|
||||
uint32_t kbase_gator_instr_hwcnt_dump_complete(
|
||||
struct kbase_gator_hwcnt_handles *opaque_handles,
|
||||
uint32_t * const success)
|
||||
{
|
||||
bool ret_res, success_res;
|
||||
|
||||
if (opaque_handles && success) {
|
||||
ret_res = kbase_instr_hwcnt_dump_complete(opaque_handles->kctx,
|
||||
&success_res);
|
||||
*success = (uint32_t)success_res;
|
||||
return (uint32_t)(ret_res != 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete);
|
||||
|
||||
uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles)
|
||||
{
|
||||
if (opaque_handles)
|
||||
return (kbase_instr_hwcnt_request_dump(
|
||||
opaque_handles->kctx) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq);
|
||||
219
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_api.h
Normal file
219
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_api.h
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_GATOR_API_H_
|
||||
#define _KBASE_GATOR_API_H_
|
||||
|
||||
/**
|
||||
* @brief This file describes the API used by Gator to fetch hardware counters.
|
||||
*/
|
||||
|
||||
/* This define is used by the gator kernel module compile to select which DDK
|
||||
* API calling convention to use. If not defined (legacy DDK) gator assumes
|
||||
* version 1. The version to DDK release mapping is:
|
||||
* Version 1 API: DDK versions r1px, r2px
|
||||
* Version 2 API: DDK versions r3px, r4px
|
||||
* Version 3 API: DDK version r5p0 and newer
|
||||
*
|
||||
* API Usage
|
||||
* =========
|
||||
*
|
||||
* 1] Call kbase_gator_hwcnt_init_names() to return the list of short counter
|
||||
* names for the GPU present in this device.
|
||||
*
|
||||
* 2] Create a kbase_gator_hwcnt_info structure and set the counter enables for
|
||||
* the counters you want enabled. The enables can all be set for simplicity in
|
||||
* most use cases, but disabling some will let you minimize bandwidth impact.
|
||||
*
|
||||
* 3] Call kbase_gator_hwcnt_init() using the above structure, to create a
|
||||
* counter context. On successful return the DDK will have populated the
|
||||
* structure with a variety of useful information.
|
||||
*
|
||||
* 4] Call kbase_gator_hwcnt_dump_irq() to queue a non-blocking request for a
|
||||
* counter dump. If this returns a non-zero value the request has been queued,
|
||||
* otherwise the driver has been unable to do so (typically because of another
|
||||
* user of the instrumentation exists concurrently).
|
||||
*
|
||||
* 5] Call kbase_gator_hwcnt_dump_complete() to test whether the previously
|
||||
* requested dump has been succesful. If this returns non-zero the counter dump
|
||||
* has resolved, but the value of *success must also be tested as the dump
|
||||
* may have not been successful. If it returns zero the counter dump was
|
||||
* abandoned due to the device being busy (typically because of another
|
||||
* user of the instrumentation exists concurrently).
|
||||
*
|
||||
* 6] Process the counters stored in the buffer pointed to by ...
|
||||
*
|
||||
* kbase_gator_hwcnt_info->kernel_dump_buffer
|
||||
*
|
||||
* In pseudo code you can find all of the counters via this approach:
|
||||
*
|
||||
*
|
||||
* hwcnt_info # pointer to kbase_gator_hwcnt_info structure
|
||||
* hwcnt_name # pointer to name list
|
||||
*
|
||||
* u32 * hwcnt_data = (u32*)hwcnt_info->kernel_dump_buffer
|
||||
*
|
||||
* # Iterate over each 64-counter block in this GPU configuration
|
||||
* for( i = 0; i < hwcnt_info->nr_hwc_blocks; i++) {
|
||||
* hwc_type type = hwcnt_info->hwc_layout[i];
|
||||
*
|
||||
* # Skip reserved type blocks - they contain no counters at all
|
||||
* if( type == RESERVED_BLOCK ) {
|
||||
* continue;
|
||||
* }
|
||||
*
|
||||
* size_t name_offset = type * 64;
|
||||
* size_t data_offset = i * 64;
|
||||
*
|
||||
* # Iterate over the names of the counters in this block type
|
||||
* for( j = 0; j < 64; j++) {
|
||||
* const char * name = hwcnt_name[name_offset+j];
|
||||
*
|
||||
* # Skip empty name strings - there is no counter here
|
||||
* if( name[0] == '\0' ) {
|
||||
* continue;
|
||||
* }
|
||||
*
|
||||
* u32 data = hwcnt_data[data_offset+j];
|
||||
*
|
||||
* printk( "COUNTER: %s DATA: %u\n", name, data );
|
||||
* }
|
||||
* }
|
||||
*
|
||||
*
|
||||
* Note that in most implementations you typically want to either SUM or
|
||||
* AVERAGE multiple instances of the same counter if, for example, you have
|
||||
* multiple shader cores or multiple L2 caches. The most sensible view for
|
||||
* analysis is to AVERAGE shader core counters, but SUM L2 cache and MMU
|
||||
* counters.
|
||||
*
|
||||
* 7] Goto 4, repeating until you want to stop collecting counters.
|
||||
*
|
||||
* 8] Release the dump resources by calling kbase_gator_hwcnt_term().
|
||||
*
|
||||
* 9] Release the name table resources by calling
|
||||
* kbase_gator_hwcnt_term_names(). This function must only be called if
|
||||
* init_names() returned a non-NULL value.
|
||||
**/
|
||||
|
||||
#define MALI_DDK_GATOR_API_VERSION 3
|
||||
|
||||
enum hwc_type {
|
||||
JM_BLOCK = 0,
|
||||
TILER_BLOCK,
|
||||
SHADER_BLOCK,
|
||||
MMU_L2_BLOCK,
|
||||
RESERVED_BLOCK
|
||||
};
|
||||
|
||||
struct kbase_gator_hwcnt_info {
|
||||
/* Passed from Gator to kbase */
|
||||
|
||||
/* the bitmask of enabled hardware counters for each counter block */
|
||||
uint16_t bitmask[4];
|
||||
|
||||
/* Passed from kbase to Gator */
|
||||
|
||||
/* ptr to counter dump memory */
|
||||
void *kernel_dump_buffer;
|
||||
|
||||
/* size of counter dump memory */
|
||||
uint32_t size;
|
||||
|
||||
/* the ID of the Mali device */
|
||||
uint32_t gpu_id;
|
||||
|
||||
/* the number of shader cores in the GPU */
|
||||
uint32_t nr_cores;
|
||||
|
||||
/* the number of core groups */
|
||||
uint32_t nr_core_groups;
|
||||
|
||||
/* the memory layout of the performance counters */
|
||||
enum hwc_type *hwc_layout;
|
||||
|
||||
/* the total number of hardware couter blocks */
|
||||
uint32_t nr_hwc_blocks;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Opaque block of Mali data which Gator needs to return to the API later.
|
||||
*/
|
||||
struct kbase_gator_hwcnt_handles;
|
||||
|
||||
/**
|
||||
* @brief Initialize the resources Gator needs for performance profiling.
|
||||
*
|
||||
* @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the Mali
|
||||
* specific information that will be returned to Gator. On entry Gator must have populated the
|
||||
* 'bitmask' field with the counters it wishes to enable for each class of counter block.
|
||||
* Each entry in the array corresponds to a single counter class based on the "hwc_type"
|
||||
* enumeration, and each bit corresponds to an enable for 4 sequential counters (LSB enables
|
||||
* the first 4 counters in the block, and so on). See the GPU counter array as returned by
|
||||
* kbase_gator_hwcnt_get_names() for the index values of each counter for the curernt GPU.
|
||||
*
|
||||
* @return Pointer to an opaque handle block on success, NULL on error.
|
||||
*/
|
||||
extern struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info);
|
||||
|
||||
/**
|
||||
* @brief Free all resources once Gator has finished using performance counters.
|
||||
*
|
||||
* @param in_out_info A pointer to a structure containing the enabled counters passed from Gator and all the
|
||||
* Mali specific information that will be returned to Gator.
|
||||
* @param opaque_handles A wrapper structure for kbase structures.
|
||||
*/
|
||||
extern void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct kbase_gator_hwcnt_handles *opaque_handles);
|
||||
|
||||
/**
|
||||
* @brief Poll whether a counter dump is successful.
|
||||
*
|
||||
* @param opaque_handles A wrapper structure for kbase structures.
|
||||
* @param[out] success Non-zero on success, zero on failure.
|
||||
*
|
||||
* @return Zero if the dump is still pending, non-zero if the dump has completed. Note that a
|
||||
* completed dump may not have dumped succesfully, so the caller must test for both
|
||||
* a completed and successful dump before processing counters.
|
||||
*/
|
||||
extern uint32_t kbase_gator_instr_hwcnt_dump_complete(struct kbase_gator_hwcnt_handles *opaque_handles, uint32_t * const success);
|
||||
|
||||
/**
|
||||
* @brief Request the generation of a new counter dump.
|
||||
*
|
||||
* @param opaque_handles A wrapper structure for kbase structures.
|
||||
*
|
||||
* @return Zero if the hardware device is busy and cannot handle the request, non-zero otherwise.
|
||||
*/
|
||||
extern uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles);
|
||||
|
||||
/**
|
||||
* @brief This function is used to fetch the names table based on the Mali device in use.
|
||||
*
|
||||
* @param[out] total_counters The total number of counters short names in the Mali devices' list.
|
||||
*
|
||||
* @return Pointer to an array of strings of length *total_counters.
|
||||
*/
|
||||
extern const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters);
|
||||
|
||||
/**
|
||||
* @brief This function is used to terminate the use of the names table.
|
||||
*
|
||||
* This function must only be called if the initial call to kbase_gator_hwcnt_init_names returned a non-NULL value.
|
||||
*/
|
||||
extern void kbase_gator_hwcnt_term_names(void);
|
||||
|
||||
#endif
|
||||
2159
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_hwcnt_names.h
Normal file
2159
drivers/gpu/arm/t72x/r7p0/mali_kbase_gator_hwcnt_names.h
Normal file
File diff suppressed because it is too large
Load diff
99
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpu_memory_debugfs.c
Normal file
99
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpu_memory_debugfs.c
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_gpu_memory_debugfs.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
/** Show callback for the @c gpu_memory debugfs file.
|
||||
*
|
||||
* This function is called to get the contents of the @c gpu_memory debugfs
|
||||
* file. This is a report of current gpu memory usage.
|
||||
*
|
||||
* @param sfile The debugfs entry
|
||||
* @param data Data associated with the entry
|
||||
*
|
||||
* @return 0 if successfully prints data in debugfs entry file
|
||||
* -1 if it encountered an error
|
||||
*/
|
||||
extern int gpu_memory_seq_show(struct seq_file *sfile, void *data);
|
||||
#ifdef MALI_SEC_INTEGRATION
|
||||
static int kbasep_gpu_memory_seq_show(struct seq_file *sfile, void *data)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
struct list_head *entry;
|
||||
const struct list_head *kbdev_list;
|
||||
|
||||
kbdev_list = kbase_dev_list_get();
|
||||
list_for_each(entry, kbdev_list) {
|
||||
struct kbase_device *kbdev = NULL;
|
||||
struct kbasep_kctx_list_element *element;
|
||||
|
||||
kbdev = list_entry(entry, struct kbase_device, entry);
|
||||
/* output the total memory usage and cap for this device */
|
||||
ret = seq_printf(sfile, "%-16s %10u\n",
|
||||
kbdev->devname,
|
||||
atomic_read(&(kbdev->memdev.used_pages)));
|
||||
mutex_lock(&kbdev->kctx_list_lock);
|
||||
list_for_each_entry(element, &kbdev->kctx_list, link) {
|
||||
/* output the memory usage and cap for each kctx
|
||||
* opened on this device */
|
||||
ret = seq_printf(sfile, " %s-0x%p %10u\n",
|
||||
"kctx",
|
||||
element->kctx,
|
||||
atomic_read(&(element->kctx->used_pages)));
|
||||
}
|
||||
mutex_unlock(&kbdev->kctx_list_lock);
|
||||
}
|
||||
kbase_dev_list_put(kbdev_list);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* File operations related to debugfs entry for gpu_memory
|
||||
*/
|
||||
static int kbasep_gpu_memory_debugfs_open(struct inode *in, struct file *file)
|
||||
{
|
||||
return single_open(file, gpu_memory_seq_show , NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations kbasep_gpu_memory_debugfs_fops = {
|
||||
.open = kbasep_gpu_memory_debugfs_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize debugfs entry for gpu_memory
|
||||
*/
|
||||
void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev)
|
||||
{
|
||||
debugfs_create_file("gpu_memory", S_IRUGO,
|
||||
kbdev->mali_debugfs_directory, NULL,
|
||||
&kbasep_gpu_memory_debugfs_fops);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* Stub functions for when debugfs is disabled
|
||||
*/
|
||||
void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
38
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpu_memory_debugfs.h
Normal file
38
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpu_memory_debugfs.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_gpu_memory_debugfs.h
|
||||
* Header file for gpu_memory entry in debugfs
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_GPU_MEMORY_H
|
||||
#define _KBASE_GPU_MEMORY_H
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
/**
|
||||
* @brief Initialize gpu_memory debugfs entry
|
||||
*/
|
||||
void kbasep_gpu_memory_debugfs_init(struct kbase_device *kbdev);
|
||||
|
||||
#endif /*_KBASE_GPU_MEMORY_H*/
|
||||
299
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops.c
Normal file
299
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops.c
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel property query APIs
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <mali_kbase_gpuprops.h>
|
||||
#include <mali_kbase_config_defaults.h>
|
||||
#include <mali_kbase_hwaccess_gpuprops.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
/**
|
||||
* KBASE_UBFX32 - Extracts bits from a 32-bit bitfield.
|
||||
* @value: The value from which to extract bits.
|
||||
* @offset: The first bit to extract (0 being the LSB).
|
||||
* @size: The number of bits to extract.
|
||||
*
|
||||
* Context: @offset + @size <= 32.
|
||||
*
|
||||
* Return: Bits [@offset, @offset + @size) from @value.
|
||||
*/
|
||||
/* from mali_cdsb.h */
|
||||
#define KBASE_UBFX32(value, offset, size) \
|
||||
(((u32)(value) >> (u32)(offset)) & (u32)((1ULL << (u32)(size)) - 1))
|
||||
|
||||
int kbase_gpuprops_uk_get_props(struct kbase_context *kctx, struct kbase_uk_gpuprops * const kbase_props)
|
||||
{
|
||||
kbase_gpu_clk_speed_func get_gpu_speed_mhz;
|
||||
u32 gpu_speed_mhz;
|
||||
int rc = 1;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kctx);
|
||||
KBASE_DEBUG_ASSERT(NULL != kbase_props);
|
||||
|
||||
/* Current GPU speed is requested from the system integrator via the GPU_SPEED_FUNC function.
|
||||
* If that function fails, or the function is not provided by the system integrator, we report the maximum
|
||||
* GPU speed as specified by GPU_FREQ_KHZ_MAX.
|
||||
*/
|
||||
get_gpu_speed_mhz = (kbase_gpu_clk_speed_func) GPU_SPEED_FUNC;
|
||||
if (get_gpu_speed_mhz != NULL) {
|
||||
rc = get_gpu_speed_mhz(&gpu_speed_mhz);
|
||||
#ifdef CONFIG_MALI_DEBUG
|
||||
/* Issue a warning message when the reported GPU speed falls outside the min/max range */
|
||||
if (rc == 0) {
|
||||
u32 gpu_speed_khz = gpu_speed_mhz * 1000;
|
||||
|
||||
if (gpu_speed_khz < kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min ||
|
||||
gpu_speed_khz > kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max)
|
||||
dev_warn(kctx->kbdev->dev, "GPU Speed is outside of min/max range (got %lu Khz, min %lu Khz, max %lu Khz)\n",
|
||||
(unsigned long)gpu_speed_khz,
|
||||
(unsigned long)kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_min,
|
||||
(unsigned long)kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max);
|
||||
}
|
||||
#endif /* CONFIG_MALI_DEBUG */
|
||||
}
|
||||
if (kctx->kbdev->clock) {
|
||||
gpu_speed_mhz = clk_get_rate(kctx->kbdev->clock) / 1000000;
|
||||
rc = 0;
|
||||
}
|
||||
if (rc != 0)
|
||||
gpu_speed_mhz = kctx->kbdev->gpu_props.props.core_props.gpu_freq_khz_max / 1000;
|
||||
|
||||
kctx->kbdev->gpu_props.props.core_props.gpu_speed_mhz = gpu_speed_mhz;
|
||||
|
||||
memcpy(&kbase_props->props, &kctx->kbdev->gpu_props.props, sizeof(kbase_props->props));
|
||||
|
||||
/* Before API 8.2 they expect L3 cache info here, which was always 0 */
|
||||
if (kctx->api_version < KBASE_API_VERSION(8, 2))
|
||||
kbase_props->props.raw_props.suspend_size = 0;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kbase_gpuprops_construct_coherent_groups(base_gpu_props * const props)
|
||||
{
|
||||
struct mali_base_gpu_coherent_group *current_group;
|
||||
u64 group_present;
|
||||
u64 group_mask;
|
||||
u64 first_set, first_set_prev;
|
||||
u32 num_groups = 0;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != props);
|
||||
|
||||
props->coherency_info.coherency = props->raw_props.mem_features;
|
||||
props->coherency_info.num_core_groups = hweight64(props->raw_props.l2_present);
|
||||
|
||||
if (props->coherency_info.coherency & GROUPS_L2_COHERENT) {
|
||||
/* Group is l2 coherent */
|
||||
group_present = props->raw_props.l2_present;
|
||||
} else {
|
||||
/* Group is l1 coherent */
|
||||
group_present = props->raw_props.shader_present;
|
||||
}
|
||||
|
||||
/*
|
||||
* The coherent group mask can be computed from the l2 present
|
||||
* register.
|
||||
*
|
||||
* For the coherent group n:
|
||||
* group_mask[n] = (first_set[n] - 1) & ~(first_set[n-1] - 1)
|
||||
* where first_set is group_present with only its nth set-bit kept
|
||||
* (i.e. the position from where a new group starts).
|
||||
*
|
||||
* For instance if the groups are l2 coherent and l2_present=0x0..01111:
|
||||
* The first mask is:
|
||||
* group_mask[1] = (first_set[1] - 1) & ~(first_set[0] - 1)
|
||||
* = (0x0..010 - 1) & ~(0x0..01 - 1)
|
||||
* = 0x0..00f
|
||||
* The second mask is:
|
||||
* group_mask[2] = (first_set[2] - 1) & ~(first_set[1] - 1)
|
||||
* = (0x0..100 - 1) & ~(0x0..010 - 1)
|
||||
* = 0x0..0f0
|
||||
* And so on until all the bits from group_present have been cleared
|
||||
* (i.e. there is no group left).
|
||||
*/
|
||||
|
||||
current_group = props->coherency_info.group;
|
||||
first_set = group_present & ~(group_present - 1);
|
||||
|
||||
while (group_present != 0 && num_groups < BASE_MAX_COHERENT_GROUPS) {
|
||||
group_present -= first_set; /* Clear the current group bit */
|
||||
first_set_prev = first_set;
|
||||
|
||||
first_set = group_present & ~(group_present - 1);
|
||||
group_mask = (first_set - 1) & ~(first_set_prev - 1);
|
||||
|
||||
/* Populate the coherent_group structure for each group */
|
||||
current_group->core_mask = group_mask & props->raw_props.shader_present;
|
||||
current_group->num_cores = hweight64(current_group->core_mask);
|
||||
|
||||
num_groups++;
|
||||
current_group++;
|
||||
}
|
||||
|
||||
if (group_present != 0)
|
||||
pr_warn("Too many coherent groups (keeping only %d groups).\n", BASE_MAX_COHERENT_GROUPS);
|
||||
|
||||
props->coherency_info.num_groups = num_groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_gpuprops_get_props - Get the GPU configuration
|
||||
* @gpu_props: The &base_gpu_props structure
|
||||
* @kbdev: The &struct kbase_device structure for the device
|
||||
*
|
||||
* Fill the &base_gpu_props structure with values from the GPU configuration
|
||||
* registers. Only the raw properties are filled in this function
|
||||
*/
|
||||
static void kbase_gpuprops_get_props(base_gpu_props * const gpu_props, struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_gpuprops_regdump regdump;
|
||||
int i;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kbdev);
|
||||
KBASE_DEBUG_ASSERT(NULL != gpu_props);
|
||||
|
||||
/* Dump relevant registers */
|
||||
kbase_backend_gpuprops_get(kbdev, ®dump);
|
||||
|
||||
gpu_props->raw_props.gpu_id = regdump.gpu_id;
|
||||
gpu_props->raw_props.tiler_features = regdump.tiler_features;
|
||||
gpu_props->raw_props.mem_features = regdump.mem_features;
|
||||
gpu_props->raw_props.mmu_features = regdump.mmu_features;
|
||||
gpu_props->raw_props.l2_features = regdump.l2_features;
|
||||
gpu_props->raw_props.suspend_size = regdump.suspend_size;
|
||||
|
||||
gpu_props->raw_props.as_present = regdump.as_present;
|
||||
gpu_props->raw_props.js_present = regdump.js_present;
|
||||
gpu_props->raw_props.shader_present = ((u64) regdump.shader_present_hi << 32) + regdump.shader_present_lo;
|
||||
gpu_props->raw_props.tiler_present = ((u64) regdump.tiler_present_hi << 32) + regdump.tiler_present_lo;
|
||||
gpu_props->raw_props.l2_present = ((u64) regdump.l2_present_hi << 32) + regdump.l2_present_lo;
|
||||
|
||||
for (i = 0; i < GPU_MAX_JOB_SLOTS; i++)
|
||||
gpu_props->raw_props.js_features[i] = regdump.js_features[i];
|
||||
|
||||
for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
|
||||
gpu_props->raw_props.texture_features[i] = regdump.texture_features[i];
|
||||
|
||||
gpu_props->raw_props.thread_max_barrier_size = regdump.thread_max_barrier_size;
|
||||
gpu_props->raw_props.thread_max_threads = regdump.thread_max_threads;
|
||||
gpu_props->raw_props.thread_max_workgroup_size = regdump.thread_max_workgroup_size;
|
||||
gpu_props->raw_props.thread_features = regdump.thread_features;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* kbase_gpuprops_calculate_props - Calculate the derived properties
|
||||
* @gpu_props: The &base_gpu_props structure
|
||||
* @kbdev: The &struct kbase_device structure for the device
|
||||
*
|
||||
* Fill the &base_gpu_props structure with values derived from the GPU
|
||||
* configuration registers
|
||||
*/
|
||||
static void kbase_gpuprops_calculate_props(base_gpu_props * const gpu_props, struct kbase_device *kbdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Populate the base_gpu_props structure */
|
||||
gpu_props->core_props.version_status = KBASE_UBFX32(gpu_props->raw_props.gpu_id, 0U, 4);
|
||||
gpu_props->core_props.minor_revision = KBASE_UBFX32(gpu_props->raw_props.gpu_id, 4U, 8);
|
||||
gpu_props->core_props.major_revision = KBASE_UBFX32(gpu_props->raw_props.gpu_id, 12U, 4);
|
||||
gpu_props->core_props.product_id = KBASE_UBFX32(gpu_props->raw_props.gpu_id, 16U, 16);
|
||||
gpu_props->core_props.log2_program_counter_size = KBASE_GPU_PC_SIZE_LOG2;
|
||||
gpu_props->core_props.gpu_available_memory_size = totalram_pages << PAGE_SHIFT;
|
||||
|
||||
for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
|
||||
gpu_props->core_props.texture_features[i] = gpu_props->raw_props.texture_features[i];
|
||||
|
||||
gpu_props->l2_props.log2_line_size = KBASE_UBFX32(gpu_props->raw_props.l2_features, 0U, 8);
|
||||
gpu_props->l2_props.log2_cache_size = KBASE_UBFX32(gpu_props->raw_props.l2_features, 16U, 8);
|
||||
|
||||
/* Field with number of l2 slices is added to MEM_FEATURES register
|
||||
* since t76x. Below code assumes that for older GPU reserved bits will
|
||||
* be read as zero. */
|
||||
gpu_props->l2_props.num_l2_slices =
|
||||
KBASE_UBFX32(gpu_props->raw_props.mem_features, 8U, 4) + 1;
|
||||
|
||||
gpu_props->tiler_props.bin_size_bytes = 1 << KBASE_UBFX32(gpu_props->raw_props.tiler_features, 0U, 6);
|
||||
gpu_props->tiler_props.max_active_levels = KBASE_UBFX32(gpu_props->raw_props.tiler_features, 8U, 4);
|
||||
|
||||
if (gpu_props->raw_props.thread_max_threads == 0)
|
||||
gpu_props->thread_props.max_threads = THREAD_MT_DEFAULT;
|
||||
else
|
||||
gpu_props->thread_props.max_threads = gpu_props->raw_props.thread_max_threads;
|
||||
|
||||
if (gpu_props->raw_props.thread_max_workgroup_size == 0)
|
||||
gpu_props->thread_props.max_workgroup_size = THREAD_MWS_DEFAULT;
|
||||
else
|
||||
gpu_props->thread_props.max_workgroup_size = gpu_props->raw_props.thread_max_workgroup_size;
|
||||
|
||||
if (gpu_props->raw_props.thread_max_barrier_size == 0)
|
||||
gpu_props->thread_props.max_barrier_size = THREAD_MBS_DEFAULT;
|
||||
else
|
||||
gpu_props->thread_props.max_barrier_size = gpu_props->raw_props.thread_max_barrier_size;
|
||||
|
||||
gpu_props->thread_props.max_registers = KBASE_UBFX32(gpu_props->raw_props.thread_features, 0U, 16);
|
||||
gpu_props->thread_props.max_task_queue = KBASE_UBFX32(gpu_props->raw_props.thread_features, 16U, 8);
|
||||
gpu_props->thread_props.max_thread_group_split = KBASE_UBFX32(gpu_props->raw_props.thread_features, 24U, 6);
|
||||
gpu_props->thread_props.impl_tech = KBASE_UBFX32(gpu_props->raw_props.thread_features, 30U, 2);
|
||||
|
||||
/* If values are not specified, then use defaults */
|
||||
if (gpu_props->thread_props.max_registers == 0) {
|
||||
gpu_props->thread_props.max_registers = THREAD_MR_DEFAULT;
|
||||
gpu_props->thread_props.max_task_queue = THREAD_MTQ_DEFAULT;
|
||||
gpu_props->thread_props.max_thread_group_split = THREAD_MTGS_DEFAULT;
|
||||
}
|
||||
/* Initialize the coherent_group structure for each group */
|
||||
kbase_gpuprops_construct_coherent_groups(gpu_props);
|
||||
}
|
||||
|
||||
void kbase_gpuprops_set(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_gpu_props *gpu_props;
|
||||
struct gpu_raw_gpu_props *raw;
|
||||
|
||||
KBASE_DEBUG_ASSERT(NULL != kbdev);
|
||||
gpu_props = &kbdev->gpu_props;
|
||||
raw = &gpu_props->props.raw_props;
|
||||
|
||||
/* Initialize the base_gpu_props structure from the hardware */
|
||||
kbase_gpuprops_get_props(&gpu_props->props, kbdev);
|
||||
|
||||
/* Populate the derived properties */
|
||||
kbase_gpuprops_calculate_props(&gpu_props->props, kbdev);
|
||||
|
||||
/* Populate kbase-only fields */
|
||||
gpu_props->l2_props.associativity = KBASE_UBFX32(raw->l2_features, 8U, 8);
|
||||
gpu_props->l2_props.external_bus_width = KBASE_UBFX32(raw->l2_features, 24U, 8);
|
||||
|
||||
gpu_props->mem.core_group = KBASE_UBFX32(raw->mem_features, 0U, 1);
|
||||
|
||||
gpu_props->mmu.va_bits = KBASE_UBFX32(raw->mmu_features, 0U, 8);
|
||||
gpu_props->mmu.pa_bits = KBASE_UBFX32(raw->mmu_features, 8U, 8);
|
||||
|
||||
gpu_props->num_cores = hweight64(raw->shader_present);
|
||||
gpu_props->num_core_groups = hweight64(raw->l2_present);
|
||||
gpu_props->num_address_spaces = hweight32(raw->as_present);
|
||||
gpu_props->num_job_slots = hweight32(raw->js_present);
|
||||
}
|
||||
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops.h
Normal file
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_gpuprops.h
|
||||
* Base kernel property query APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_GPUPROPS_H_
|
||||
#define _KBASE_GPUPROPS_H_
|
||||
|
||||
#include "mali_kbase_gpuprops_types.h"
|
||||
|
||||
/* Forward definition - see mali_kbase.h */
|
||||
struct kbase_device;
|
||||
|
||||
/**
|
||||
* @brief Set up Kbase GPU properties.
|
||||
*
|
||||
* Set up Kbase GPU properties with information from the GPU registers
|
||||
*
|
||||
* @param kbdev The struct kbase_device structure for the device
|
||||
*/
|
||||
void kbase_gpuprops_set(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* @brief Provide GPU properties to userside through UKU call.
|
||||
*
|
||||
* Fill the struct kbase_uk_gpuprops with values from GPU configuration registers.
|
||||
*
|
||||
* @param kctx The struct kbase_context structure
|
||||
* @param kbase_props A copy of the struct kbase_uk_gpuprops structure from userspace
|
||||
*
|
||||
* @return 0 on success. Any other value indicates failure.
|
||||
*/
|
||||
int kbase_gpuprops_uk_get_props(struct kbase_context *kctx, struct kbase_uk_gpuprops * const kbase_props);
|
||||
|
||||
#endif /* _KBASE_GPUPROPS_H_ */
|
||||
91
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops_types.h
Normal file
91
drivers/gpu/arm/t72x/r7p0/mali_kbase_gpuprops_types.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_gpuprops_types.h
|
||||
* Base kernel property query APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_GPUPROPS_TYPES_H_
|
||||
#define _KBASE_GPUPROPS_TYPES_H_
|
||||
|
||||
#include "mali_base_kernel.h"
|
||||
|
||||
#define KBASE_GPU_SPEED_MHZ 123
|
||||
#define KBASE_GPU_PC_SIZE_LOG2 24U
|
||||
|
||||
struct kbase_gpuprops_regdump {
|
||||
u32 gpu_id;
|
||||
u32 l2_features;
|
||||
u32 suspend_size; /* API 8.2+ */
|
||||
u32 tiler_features;
|
||||
u32 mem_features;
|
||||
u32 mmu_features;
|
||||
u32 as_present;
|
||||
u32 js_present;
|
||||
u32 thread_max_threads;
|
||||
u32 thread_max_workgroup_size;
|
||||
u32 thread_max_barrier_size;
|
||||
u32 thread_features;
|
||||
u32 texture_features[BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS];
|
||||
u32 js_features[GPU_MAX_JOB_SLOTS];
|
||||
u32 shader_present_lo;
|
||||
u32 shader_present_hi;
|
||||
u32 tiler_present_lo;
|
||||
u32 tiler_present_hi;
|
||||
u32 l2_present_lo;
|
||||
u32 l2_present_hi;
|
||||
};
|
||||
|
||||
struct kbase_gpu_cache_props {
|
||||
u8 associativity;
|
||||
u8 external_bus_width;
|
||||
};
|
||||
|
||||
struct kbase_gpu_mem_props {
|
||||
u8 core_group;
|
||||
};
|
||||
|
||||
struct kbase_gpu_mmu_props {
|
||||
u8 va_bits;
|
||||
u8 pa_bits;
|
||||
};
|
||||
|
||||
struct kbase_gpu_props {
|
||||
/* kernel-only properties */
|
||||
u8 num_cores;
|
||||
u8 num_core_groups;
|
||||
u8 num_address_spaces;
|
||||
u8 num_job_slots;
|
||||
|
||||
struct kbase_gpu_cache_props l2_props;
|
||||
|
||||
struct kbase_gpu_mem_props mem;
|
||||
struct kbase_gpu_mmu_props mmu;
|
||||
|
||||
/**
|
||||
* Implementation specific irq throttle value (us), should be adjusted during integration.
|
||||
*/
|
||||
int irq_throttle_time_us;
|
||||
|
||||
/* Properties shared with userspace */
|
||||
base_gpu_props props;
|
||||
};
|
||||
|
||||
#endif /* _KBASE_GPUPROPS_TYPES_H_ */
|
||||
214
drivers/gpu/arm/t72x/r7p0/mali_kbase_hw.c
Normal file
214
drivers/gpu/arm/t72x/r7p0/mali_kbase_hw.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Run-time work-arounds helpers
|
||||
*/
|
||||
|
||||
#include <mali_base_hwconfig_features.h>
|
||||
#include <mali_base_hwconfig_issues.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
#include "mali_kbase.h"
|
||||
#include "mali_kbase_hw.h"
|
||||
|
||||
void kbase_hw_set_features_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
const enum base_hw_feature *features;
|
||||
u32 gpu_id;
|
||||
|
||||
gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
|
||||
gpu_id &= GPU_ID_VERSION_PRODUCT_ID;
|
||||
gpu_id = gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT;
|
||||
|
||||
switch (gpu_id) {
|
||||
case GPU_ID_PI_TFRX:
|
||||
/* FALLTHROUGH */
|
||||
case GPU_ID_PI_T86X:
|
||||
features = base_hw_features_tFxx;
|
||||
break;
|
||||
case GPU_ID_PI_T83X:
|
||||
features = base_hw_features_t83x;
|
||||
break;
|
||||
case GPU_ID_PI_T82X:
|
||||
features = base_hw_features_t82x;
|
||||
break;
|
||||
case GPU_ID_PI_T76X:
|
||||
features = base_hw_features_t76x;
|
||||
break;
|
||||
case GPU_ID_PI_T72X:
|
||||
features = base_hw_features_t72x;
|
||||
break;
|
||||
case GPU_ID_PI_T62X:
|
||||
features = base_hw_features_t62x;
|
||||
break;
|
||||
case GPU_ID_PI_T60X:
|
||||
features = base_hw_features_t60x;
|
||||
break;
|
||||
default:
|
||||
features = base_hw_features_generic;
|
||||
break;
|
||||
}
|
||||
|
||||
for (; *features != BASE_HW_FEATURE_END; features++)
|
||||
set_bit(*features, &kbdev->hw_features_mask[0]);
|
||||
}
|
||||
|
||||
int kbase_hw_set_issues_mask(struct kbase_device *kbdev)
|
||||
{
|
||||
const enum base_hw_issue *issues;
|
||||
u32 gpu_id;
|
||||
u32 impl_tech;
|
||||
|
||||
gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
|
||||
impl_tech = kbdev->gpu_props.props.thread_props.impl_tech;
|
||||
|
||||
if (impl_tech != IMPLEMENTATION_MODEL) {
|
||||
switch (gpu_id) {
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_15DEV0):
|
||||
issues = base_hw_issues_t60x_r0p0_15dev0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 0, GPU_ID_S_EAC):
|
||||
issues = base_hw_issues_t60x_r0p0_eac;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T60X, 0, 1, 0):
|
||||
issues = base_hw_issues_t60x_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T62X, 0, 1, 0):
|
||||
issues = base_hw_issues_t62x_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 0, 1):
|
||||
issues = base_hw_issues_t62x_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T62X, 1, 1, 0):
|
||||
issues = base_hw_issues_t62x_r1p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 0, 1):
|
||||
issues = base_hw_issues_t76x_r0p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 1, 1):
|
||||
issues = base_hw_issues_t76x_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 1, 9):
|
||||
issues = base_hw_issues_t76x_r0p1_50rel0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 2, 1):
|
||||
issues = base_hw_issues_t76x_r0p2;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 0, 3, 1):
|
||||
issues = base_hw_issues_t76x_r0p3;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T76X, 1, 0, 0):
|
||||
issues = base_hw_issues_t76x_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 1):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T72X, 0, 0, 2):
|
||||
issues = base_hw_issues_t72x_r0p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T72X, 1, 0, 0):
|
||||
issues = base_hw_issues_t72x_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T72X, 1, 1, 0):
|
||||
issues = base_hw_issues_t72x_r1p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_TFRX, 0, 1, 2):
|
||||
issues = base_hw_issues_tFRx_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_TFRX, 0, 2, 0):
|
||||
issues = base_hw_issues_tFRx_r0p2;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_TFRX, 1, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_TFRX, 1, 0, 8):
|
||||
issues = base_hw_issues_tFRx_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_TFRX, 2, 0, 0):
|
||||
issues = base_hw_issues_tFRx_r2p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T86X, 0, 2, 0):
|
||||
issues = base_hw_issues_t86x_r0p2;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T86X, 1, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T86X, 1, 0, 8):
|
||||
issues = base_hw_issues_t86x_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T86X, 2, 0, 0):
|
||||
issues = base_hw_issues_t86x_r2p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T83X, 0, 1, 0):
|
||||
issues = base_hw_issues_t83x_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T83X, 1, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T83X, 1, 0, 8):
|
||||
issues = base_hw_issues_t83x_r1p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T82X, 0, 0, 0):
|
||||
issues = base_hw_issues_t82x_r0p0;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T82X, 0, 1, 0):
|
||||
issues = base_hw_issues_t82x_r0p1;
|
||||
break;
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T82X, 1, 0, 0):
|
||||
case GPU_ID_MAKE(GPU_ID_PI_T82X, 1, 0, 8):
|
||||
issues = base_hw_issues_t82x_r1p0;
|
||||
break;
|
||||
default:
|
||||
dev_err(kbdev->dev, "Unknown GPU ID %x", gpu_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* Software model */
|
||||
switch (gpu_id >> GPU_ID_VERSION_PRODUCT_ID_SHIFT) {
|
||||
case GPU_ID_PI_T60X:
|
||||
issues = base_hw_issues_model_t60x;
|
||||
break;
|
||||
case GPU_ID_PI_T62X:
|
||||
issues = base_hw_issues_model_t62x;
|
||||
break;
|
||||
case GPU_ID_PI_T72X:
|
||||
issues = base_hw_issues_model_t72x;
|
||||
break;
|
||||
case GPU_ID_PI_T76X:
|
||||
issues = base_hw_issues_model_t76x;
|
||||
break;
|
||||
case GPU_ID_PI_TFRX:
|
||||
issues = base_hw_issues_model_tFRx;
|
||||
break;
|
||||
case GPU_ID_PI_T86X:
|
||||
issues = base_hw_issues_model_t86x;
|
||||
break;
|
||||
case GPU_ID_PI_T83X:
|
||||
issues = base_hw_issues_model_t83x;
|
||||
break;
|
||||
case GPU_ID_PI_T82X:
|
||||
issues = base_hw_issues_model_t82x;
|
||||
break;
|
||||
default:
|
||||
dev_err(kbdev->dev, "Unknown GPU ID %x", gpu_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(kbdev->dev, "GPU identified as 0x%04x r%dp%d status %d", (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >> GPU_ID_VERSION_PRODUCT_ID_SHIFT, (gpu_id & GPU_ID_VERSION_MAJOR) >> GPU_ID_VERSION_MAJOR_SHIFT, (gpu_id & GPU_ID_VERSION_MINOR) >> GPU_ID_VERSION_MINOR_SHIFT, (gpu_id & GPU_ID_VERSION_STATUS) >> GPU_ID_VERSION_STATUS_SHIFT);
|
||||
|
||||
for (; *issues != BASE_HW_ISSUE_END; issues++)
|
||||
set_bit(*issues, &kbdev->hw_issues_mask[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
52
drivers/gpu/arm/t72x/r7p0/mali_kbase_hw.h
Normal file
52
drivers/gpu/arm/t72x/r7p0/mali_kbase_hw.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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
|
||||
* Run-time work-arounds helpers
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HW_H_
|
||||
#define _KBASE_HW_H_
|
||||
|
||||
#include "mali_kbase_defs.h"
|
||||
|
||||
/**
|
||||
* @brief Tell whether a work-around should be enabled
|
||||
*/
|
||||
#define kbase_hw_has_issue(kbdev, issue)\
|
||||
test_bit(issue, &(kbdev)->hw_issues_mask[0])
|
||||
|
||||
/**
|
||||
* @brief Tell whether a feature is supported
|
||||
*/
|
||||
#define kbase_hw_has_feature(kbdev, feature)\
|
||||
test_bit(feature, &(kbdev)->hw_features_mask[0])
|
||||
|
||||
/**
|
||||
* @brief Set the HW issues mask depending on the GPU ID
|
||||
*/
|
||||
int kbase_hw_set_issues_mask(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* @brief Set the features mask depending on the GPU ID
|
||||
*/
|
||||
void kbase_hw_set_features_mask(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_HW_H_ */
|
||||
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_backend.h
Normal file
54
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_backend.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* HW access backend common APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_BACKEND_H_
|
||||
#define _KBASE_HWACCESS_BACKEND_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_early_init - Perform any backend-specific initialization.
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Return: 0 on success, or an error code on failure.
|
||||
*/
|
||||
int kbase_backend_early_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_backend_late_init - Perform any backend-specific initialization.
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Return: 0 on success, or an error code on failure.
|
||||
*/
|
||||
int kbase_backend_late_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_backend_early_term - Perform any backend-specific termination.
|
||||
* @kbdev: Device pointer
|
||||
*/
|
||||
void kbase_backend_early_term(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_backend_late_term - Perform any backend-specific termination.
|
||||
* @kbdev: Device pointer
|
||||
*/
|
||||
void kbase_backend_late_term(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_BACKEND_H_ */
|
||||
37
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_defs.h
Normal file
37
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_defs.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_hwaccess_gpu_defs.h
|
||||
* HW access common definitions
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_DEFS_H_
|
||||
#define _KBASE_HWACCESS_DEFS_H_
|
||||
|
||||
#include <mali_kbase_jm_defs.h>
|
||||
|
||||
/* The kbasep_js_device_data::runpool_irq::lock (a spinlock) must be held when
|
||||
* accessing this structure */
|
||||
struct kbase_hwaccess_data {
|
||||
struct kbase_context *active_kctx;
|
||||
|
||||
struct kbase_backend_data backend;
|
||||
};
|
||||
|
||||
#endif /* _KBASE_HWACCESS_DEFS_H_ */
|
||||
35
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_gpuprops.h
Normal file
35
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_gpuprops.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base kernel property query backend APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_GPUPROPS_H_
|
||||
#define _KBASE_HWACCESS_GPUPROPS_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_gpuprops_get() - Fill @regdump with GPU properties read from
|
||||
* GPU
|
||||
* @kbdev: Device pointer
|
||||
* @regdump: Pointer to struct kbase_gpuprops_regdump structure
|
||||
*/
|
||||
void kbase_backend_gpuprops_get(struct kbase_device *kbdev,
|
||||
struct kbase_gpuprops_regdump *regdump);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_GPUPROPS_H_ */
|
||||
116
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_instr.h
Normal file
116
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_instr.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* HW Access instrumentation common APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_INSTR_H_
|
||||
#define _KBASE_HWACCESS_INSTR_H_
|
||||
|
||||
#include <mali_kbase_instr_defs.h>
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_enable_internal - Enable HW counters collection
|
||||
* @kbdev: Kbase device
|
||||
* @kctx: Kbase context
|
||||
* @setup: HW counter setup parameters
|
||||
*
|
||||
* Context: might sleep, waiting for reset to complete
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
struct kbase_uk_hwcnt_setup *setup);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_disable_internal - Disable HW counters collection
|
||||
* @kctx: Kbase context
|
||||
*
|
||||
* Context: might sleep, waiting for an ongoing dump to complete
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_hwcnt_disable_internal(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_request_dump() - Request HW counter dump from GPU
|
||||
* @kctx: Kbase context
|
||||
*
|
||||
* Caller must either wait for kbase_instr_hwcnt_dump_complete() to return true,
|
||||
* of call kbase_instr_hwcnt_wait_for_dump().
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_wait_for_dump() - Wait until pending HW counter dump has
|
||||
* completed.
|
||||
* @kctx: Kbase context
|
||||
*
|
||||
* Context: will sleep, waiting for dump to complete
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_hwcnt_wait_for_dump(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_dump_complete - Tell whether the HW counters dump has
|
||||
* completed
|
||||
* @kctx: Kbase context
|
||||
* @success: Set to true if successful
|
||||
*
|
||||
* Context: does not sleep.
|
||||
*
|
||||
* Return: true if the dump is complete
|
||||
*/
|
||||
bool kbase_instr_hwcnt_dump_complete(struct kbase_context *kctx,
|
||||
bool * const success);
|
||||
|
||||
/**
|
||||
* kbase_instr_hwcnt_clear() - Clear HW counters
|
||||
* @kctx: Kbase context
|
||||
*
|
||||
* Context: might sleep, waiting for reset to complete
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_hwcnt_clear(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_instr_backend_init() - Initialise the instrumentation backend
|
||||
* @kbdev: Kbase device
|
||||
*
|
||||
* This function should be called during driver initialization.
|
||||
*
|
||||
* Return: 0 on success
|
||||
*/
|
||||
int kbase_instr_backend_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_instr_backend_init() - Terminate the instrumentation backend
|
||||
* @kbdev: Kbase device
|
||||
*
|
||||
* This function should be called during driver termination.
|
||||
*/
|
||||
void kbase_instr_backend_term(struct kbase_device *kbdev);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_INSTR_H_ */
|
||||
328
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_jm.h
Normal file
328
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_jm.h
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* HW access job manager common APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_JM_H_
|
||||
#define _KBASE_HWACCESS_JM_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_run_atom() - Run an atom on the GPU
|
||||
* @kbdev: Device pointer
|
||||
* @atom: Atom to run
|
||||
*
|
||||
* Caller must hold the HW access lock
|
||||
*/
|
||||
void kbase_backend_run_atom(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom);
|
||||
|
||||
/**
|
||||
* kbase_backend_find_free_address_space() - Find a free address space.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* If no address spaces are currently free, then this function can evict an
|
||||
* idle context from the runpool, freeing up the address space it was using.
|
||||
*
|
||||
* The address space is marked as in use. The caller must either assign a
|
||||
* context using kbase_gpu_use_ctx(), or release it using
|
||||
* kbase_gpu_release_free_address_space()
|
||||
*
|
||||
* Return: Number of free address space, or KBASEP_AS_NR_INVALID if none
|
||||
* available
|
||||
*/
|
||||
int kbase_backend_find_free_address_space(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_backend_release_free_address_space() - Release an address space.
|
||||
* @kbdev: Device pointer
|
||||
* @as_nr: Address space to release
|
||||
*
|
||||
* The address space must have been returned by
|
||||
* kbase_gpu_find_free_address_space().
|
||||
*/
|
||||
void kbase_backend_release_free_address_space(struct kbase_device *kbdev,
|
||||
int as_nr);
|
||||
|
||||
/**
|
||||
* kbase_backend_use_ctx() - Activate a currently unscheduled context, using the
|
||||
* provided address space.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer. May be NULL
|
||||
* @as_nr: Free address space to use
|
||||
*
|
||||
* kbase_gpu_next_job() will pull atoms from the active context.
|
||||
*
|
||||
* Return: true if successful, false if ASID not assigned. If kctx->as_pending
|
||||
* is true then ASID assignment will complete at some point in the
|
||||
* future and will re-start scheduling, otherwise no ASIDs are available
|
||||
*/
|
||||
bool kbase_backend_use_ctx(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx,
|
||||
int as_nr);
|
||||
|
||||
/**
|
||||
* kbase_backend_use_ctx_sched() - Activate a context.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* kbase_gpu_next_job() will pull atoms from the active context.
|
||||
*
|
||||
* The context must already be scheduled and assigned to an address space. If
|
||||
* the context is not scheduled, then kbase_gpu_use_ctx() should be used
|
||||
* instead.
|
||||
*
|
||||
* Caller must hold runpool_irq.lock
|
||||
*
|
||||
* Return: true if context is now active, false otherwise (ie if context does
|
||||
* not have an address space assigned)
|
||||
*/
|
||||
bool kbase_backend_use_ctx_sched(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_backend_release_ctx_irq - Release a context from the GPU. This will
|
||||
* de-assign the assigned address space.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* Caller must hold as->transaction_mutex and runpool_irq.lock
|
||||
*/
|
||||
void kbase_backend_release_ctx_irq(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_backend_release_ctx_noirq - Release a context from the GPU. This will
|
||||
* de-assign the assigned address space.
|
||||
* @kbdev: Device pointer
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* Caller must hold as->transaction_mutex
|
||||
*
|
||||
* This function must perform any operations that could not be performed in IRQ
|
||||
* context by kbase_backend_release_ctx_irq().
|
||||
*/
|
||||
void kbase_backend_release_ctx_noirq(struct kbase_device *kbdev,
|
||||
struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_backend_complete_wq() - Perform backend-specific actions required on
|
||||
* completing an atom.
|
||||
* @kbdev: Device pointer
|
||||
* @katom: Pointer to the atom to complete
|
||||
*
|
||||
* This function should only be called from kbase_jd_done_worker() or
|
||||
* js_return_worker().
|
||||
*
|
||||
* Return: true if atom has completed, false if atom should be re-submitted
|
||||
*/
|
||||
void kbase_backend_complete_wq(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *katom);
|
||||
|
||||
/**
|
||||
* kbase_backend_complete_wq_post_sched - Perform backend-specific actions
|
||||
* required on completing an atom, after
|
||||
* any scheduling has taken place.
|
||||
* @kbdev: Device pointer
|
||||
* @core_req: Core requirements of atom
|
||||
* @affinity: Affinity of atom
|
||||
* @coreref_state: Coreref state of atom
|
||||
*
|
||||
* This function should only be called from kbase_jd_done_worker() or
|
||||
* js_return_worker().
|
||||
*/
|
||||
void kbase_backend_complete_wq_post_sched(struct kbase_device *kbdev,
|
||||
base_jd_core_req core_req, u64 affinity,
|
||||
enum kbase_atom_coreref_state coreref_state);
|
||||
|
||||
/**
|
||||
* kbase_backend_reset() - The GPU is being reset. Cancel all jobs on the GPU
|
||||
* and remove any others from the ringbuffers.
|
||||
* @kbdev: Device pointer
|
||||
* @end_timestamp: Timestamp of reset
|
||||
*/
|
||||
void kbase_backend_reset(struct kbase_device *kbdev, ktime_t *end_timestamp);
|
||||
|
||||
/**
|
||||
* kbase_backend_inspect_head() - Return the atom currently at the head of slot
|
||||
* @js
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
*
|
||||
* Return : Atom currently at the head of slot @js, or NULL
|
||||
*/
|
||||
struct kbase_jd_atom *kbase_backend_inspect_head(struct kbase_device *kbdev,
|
||||
int js);
|
||||
|
||||
/**
|
||||
* kbase_backend_inspect_tail - Return the atom currently at the tail of slot
|
||||
* @js
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
*
|
||||
* Return : Atom currently at the head of slot @js, or NULL
|
||||
*/
|
||||
struct kbase_jd_atom *kbase_backend_inspect_tail(struct kbase_device *kbdev,
|
||||
int js);
|
||||
|
||||
/**
|
||||
* kbase_backend_nr_atoms_on_slot() - Return the number of atoms currently on a
|
||||
* slot.
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
*
|
||||
* Return : Number of atoms currently on slot
|
||||
*/
|
||||
int kbase_backend_nr_atoms_on_slot(struct kbase_device *kbdev, int js);
|
||||
|
||||
/**
|
||||
* kbase_backend_nr_atoms_submitted() - Return the number of atoms on a slot
|
||||
* that are currently on the GPU.
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
*
|
||||
* Return : Number of atoms currently on slot @js that are currently on the GPU.
|
||||
*/
|
||||
int kbase_backend_nr_atoms_submitted(struct kbase_device *kbdev, int js);
|
||||
|
||||
/**
|
||||
* kbase_backend_ctx_count_changed() - Number of contexts ready to submit jobs
|
||||
* has changed.
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* Perform any required backend-specific actions (eg starting/stopping
|
||||
* scheduling timers).
|
||||
*/
|
||||
void kbase_backend_ctx_count_changed(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_backend_slot_free() - Return the number of jobs that can be currently
|
||||
* submitted to slot @js.
|
||||
* @kbdev: Device pointer
|
||||
* @js: Job slot to inspect
|
||||
*
|
||||
* Return : Number of jobs that can be submitted.
|
||||
*/
|
||||
int kbase_backend_slot_free(struct kbase_device *kbdev, int js);
|
||||
|
||||
/**
|
||||
* kbase_job_check_enter_disjoint - potentially leave disjoint state
|
||||
* @kbdev: kbase device
|
||||
* @target_katom: atom which is finishing
|
||||
*
|
||||
* Work out whether to leave disjoint state when finishing an atom that was
|
||||
* originated by kbase_job_check_enter_disjoint().
|
||||
*/
|
||||
void kbase_job_check_leave_disjoint(struct kbase_device *kbdev,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
|
||||
/**
|
||||
* kbase_backend_jm_kill_jobs_from_kctx - Kill all jobs that are currently
|
||||
* running from a context
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* This is used in response to a page fault to remove all jobs from the faulting
|
||||
* context from the hardware.
|
||||
*/
|
||||
void kbase_backend_jm_kill_jobs_from_kctx(struct kbase_context *kctx);
|
||||
|
||||
/**
|
||||
* kbase_jm_wait_for_zero_jobs - Wait for context to have zero jobs running, and
|
||||
* to be descheduled.
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* This should be called following kbase_js_zap_context(), to ensure the context
|
||||
* can be safely destroyed.
|
||||
*/
|
||||
void kbase_jm_wait_for_zero_jobs(struct kbase_context *kctx);
|
||||
|
||||
#if KBASE_GPU_RESET_EN
|
||||
/**
|
||||
* kbase_prepare_to_reset_gpu - Prepare for resetting the GPU.
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function just soft-stops all the slots to ensure that as many jobs as
|
||||
* possible are saved.
|
||||
*
|
||||
* Return: a boolean which should be interpreted as follows:
|
||||
* - true - Prepared for reset, kbase_reset_gpu should be called.
|
||||
* - false - Another thread is performing a reset, kbase_reset_gpu should
|
||||
* not be called.
|
||||
*/
|
||||
bool kbase_prepare_to_reset_gpu(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_reset_gpu - Reset the GPU
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function should be called after kbase_prepare_to_reset_gpu if it returns
|
||||
* true. It should never be called without a corresponding call to
|
||||
* kbase_prepare_to_reset_gpu.
|
||||
*
|
||||
* After this function is called (or not called if kbase_prepare_to_reset_gpu
|
||||
* returned false), the caller should wait for kbdev->reset_waitq to be
|
||||
* signalled to know when the reset has completed.
|
||||
*/
|
||||
void kbase_reset_gpu(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_prepare_to_reset_gpu_locked - Prepare for resetting the GPU.
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function just soft-stops all the slots to ensure that as many jobs as
|
||||
* possible are saved.
|
||||
*
|
||||
* Return: a boolean which should be interpreted as follows:
|
||||
* - true - Prepared for reset, kbase_reset_gpu should be called.
|
||||
* - false - Another thread is performing a reset, kbase_reset_gpu should
|
||||
* not be called.
|
||||
*/
|
||||
bool kbase_prepare_to_reset_gpu_locked(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_reset_gpu_locked - Reset the GPU
|
||||
* @kbdev: Device pointer
|
||||
*
|
||||
* This function should be called after kbase_prepare_to_reset_gpu if it
|
||||
* returns true. It should never be called without a corresponding call to
|
||||
* kbase_prepare_to_reset_gpu.
|
||||
*
|
||||
* After this function is called (or not called if kbase_prepare_to_reset_gpu
|
||||
* returned false), the caller should wait for kbdev->reset_waitq to be
|
||||
* signalled to know when the reset has completed.
|
||||
*/
|
||||
void kbase_reset_gpu_locked(struct kbase_device *kbdev);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* kbase_job_slot_hardstop - Hard-stop the specified job slot
|
||||
* @kctx: The kbase context that contains the job(s) that should
|
||||
* be hard-stopped
|
||||
* @js: The job slot to hard-stop
|
||||
* @target_katom: The job that should be hard-stopped (or NULL for all
|
||||
* jobs from the context)
|
||||
* Context:
|
||||
* The job slot lock must be held when calling this function.
|
||||
*/
|
||||
void kbase_job_slot_hardstop(struct kbase_context *kctx, int js,
|
||||
struct kbase_jd_atom *target_katom);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_JM_H_ */
|
||||
206
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_pm.h
Normal file
206
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_pm.h
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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_kbase_hwaccess_pm.h
|
||||
* HW access power manager common APIs
|
||||
*/
|
||||
|
||||
#ifndef _KBASE_HWACCESS_PM_H_
|
||||
#define _KBASE_HWACCESS_PM_H_
|
||||
|
||||
#include <mali_midg_regmap.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include <mali_kbase_pm_defs.h>
|
||||
|
||||
/* Forward definition - see mali_kbase.h */
|
||||
struct kbase_device;
|
||||
|
||||
/* Functions common to all HW access backends */
|
||||
|
||||
/**
|
||||
* Initialize the power management framework.
|
||||
*
|
||||
* Must be called before any other power management function
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*
|
||||
* @return 0 if the power management framework was successfully
|
||||
* initialized.
|
||||
*/
|
||||
int kbase_hwaccess_pm_init(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Terminate the power management framework.
|
||||
*
|
||||
* No power management functions may be called after this (except
|
||||
* @ref kbase_pm_init)
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_term(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* kbase_hwaccess_pm_powerup - Power up the GPU.
|
||||
* @kbdev: The kbase device structure for the device (must be a valid pointer)
|
||||
* @flags: Flags to pass on to kbase_pm_init_hw
|
||||
*
|
||||
* Power up GPU after all modules have been initialized and interrupt handlers
|
||||
* installed.
|
||||
*
|
||||
* Return: 0 if powerup was successful.
|
||||
*/
|
||||
int kbase_hwaccess_pm_powerup(struct kbase_device *kbdev,
|
||||
unsigned int flags);
|
||||
|
||||
/**
|
||||
* Halt the power management framework.
|
||||
*
|
||||
* Should ensure that no new interrupts are generated, but allow any currently
|
||||
* running interrupt handlers to complete successfully. The GPU is forced off by
|
||||
* the time this function returns, regardless of whether or not the active power
|
||||
* policy asks for the GPU to be powered off.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_halt(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Perform any backend-specific actions to suspend the GPU
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_suspend(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Perform any backend-specific actions to resume the GPU from a suspend
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_resume(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Perform any required actions for activating the GPU. Called when the first
|
||||
* context goes active.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_gpu_active(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Perform any required actions for idling the GPU. Called when the last
|
||||
* context goes idle.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*/
|
||||
void kbase_hwaccess_pm_gpu_idle(struct kbase_device *kbdev);
|
||||
|
||||
|
||||
/**
|
||||
* Set the debug core mask.
|
||||
*
|
||||
* This determines which cores the power manager is allowed to use.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a
|
||||
* valid pointer)
|
||||
* @param new_core_mask The core mask to use
|
||||
*/
|
||||
void kbase_pm_set_debug_core_mask(struct kbase_device *kbdev,
|
||||
u64 new_core_mask);
|
||||
|
||||
|
||||
/**
|
||||
* Get the current policy.
|
||||
*
|
||||
* Returns the policy that is currently active.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*
|
||||
* @return The current policy
|
||||
*/
|
||||
const struct kbase_pm_ca_policy
|
||||
*kbase_pm_ca_get_policy(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Change the policy to the one specified.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @param policy The policy to change to (valid pointer returned from
|
||||
* @ref kbase_pm_ca_list_policies)
|
||||
*/
|
||||
void kbase_pm_ca_set_policy(struct kbase_device *kbdev,
|
||||
const struct kbase_pm_ca_policy *policy);
|
||||
|
||||
/**
|
||||
* Retrieve a static list of the available policies.
|
||||
*
|
||||
* @param[out] policies An array pointer to take the list of policies. This may
|
||||
* be NULL. The contents of this array must not be
|
||||
* modified.
|
||||
*
|
||||
* @return The number of policies
|
||||
*/
|
||||
int
|
||||
kbase_pm_ca_list_policies(const struct kbase_pm_ca_policy * const **policies);
|
||||
|
||||
|
||||
/**
|
||||
* Get the current policy.
|
||||
*
|
||||
* Returns the policy that is currently active.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
*
|
||||
* @return The current policy
|
||||
*/
|
||||
const struct kbase_pm_policy *kbase_pm_get_policy(struct kbase_device *kbdev);
|
||||
|
||||
/**
|
||||
* Change the policy to the one specified.
|
||||
*
|
||||
* @param kbdev The kbase device structure for the device (must be a valid
|
||||
* pointer)
|
||||
* @param policy The policy to change to (valid pointer returned from
|
||||
* @ref kbase_pm_list_policies)
|
||||
*/
|
||||
void kbase_pm_set_policy(struct kbase_device *kbdev,
|
||||
const struct kbase_pm_policy *policy);
|
||||
|
||||
/**
|
||||
* Retrieve a static list of the available policies.
|
||||
*
|
||||
* @param[out] policies An array pointer to take the list of policies. This may
|
||||
* be NULL. The contents of this array must not be
|
||||
* modified.
|
||||
*
|
||||
* @return The number of policies
|
||||
*/
|
||||
int kbase_pm_list_policies(const struct kbase_pm_policy * const **policies);
|
||||
|
||||
#endif /* _KBASE_HWACCESS_PM_H_ */
|
||||
53
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_time.h
Normal file
53
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwaccess_time.h
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_BACKEND_TIME_H_
|
||||
#define _KBASE_BACKEND_TIME_H_
|
||||
|
||||
/**
|
||||
* kbase_backend_get_gpu_time() - Get current GPU time
|
||||
* @kbdev: Device pointer
|
||||
* @cycle_counter: Pointer to u64 to store cycle counter in
|
||||
* @system_time: Pointer to u64 to store system time in
|
||||
* @ts: Pointer to struct timespec to store current monotonic
|
||||
* time in
|
||||
*/
|
||||
void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter,
|
||||
u64 *system_time, struct timespec *ts);
|
||||
|
||||
/**
|
||||
* kbase_wait_write_flush() - Wait for GPU write flush
|
||||
* @kctx: Context pointer
|
||||
*
|
||||
* Wait 1000 GPU clock cycles. This delay is known to give the GPU time to flush
|
||||
* its write buffer.
|
||||
*
|
||||
* If GPU resets occur then the counters are reset to zero, the delay may not be
|
||||
* as expected.
|
||||
*
|
||||
* This function is only in use for BASE_HW_ISSUE_6367
|
||||
*/
|
||||
#ifndef CONFIG_MALI_NO_MALI
|
||||
void kbase_wait_write_flush(struct kbase_context *kctx);
|
||||
#endif
|
||||
|
||||
#endif /* _KBASE_BACKEND_TIME_H_ */
|
||||
66
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwcnt_reader.h
Normal file
66
drivers/gpu/arm/t72x/r7p0/mali_kbase_hwcnt_reader.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is 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 _KBASE_HWCNT_READER_H_
|
||||
#define _KBASE_HWCNT_READER_H_
|
||||
|
||||
/* The ids of ioctl commands. */
|
||||
#define KBASE_HWCNT_READER 0xBE
|
||||
#define KBASE_HWCNT_READER_GET_HWVER _IOR(KBASE_HWCNT_READER, 0x00, u32)
|
||||
#define KBASE_HWCNT_READER_GET_BUFFER_SIZE _IOR(KBASE_HWCNT_READER, 0x01, u32)
|
||||
#define KBASE_HWCNT_READER_DUMP _IOW(KBASE_HWCNT_READER, 0x10, u32)
|
||||
#define KBASE_HWCNT_READER_CLEAR _IOW(KBASE_HWCNT_READER, 0x11, u32)
|
||||
#define KBASE_HWCNT_READER_GET_BUFFER _IOR(KBASE_HWCNT_READER, 0x20,\
|
||||
struct kbase_hwcnt_reader_metadata)
|
||||
#define KBASE_HWCNT_READER_PUT_BUFFER _IOW(KBASE_HWCNT_READER, 0x21,\
|
||||
struct kbase_hwcnt_reader_metadata)
|
||||
#define KBASE_HWCNT_READER_SET_INTERVAL _IOW(KBASE_HWCNT_READER, 0x30, u32)
|
||||
#define KBASE_HWCNT_READER_ENABLE_EVENT _IOW(KBASE_HWCNT_READER, 0x40, u32)
|
||||
#define KBASE_HWCNT_READER_DISABLE_EVENT _IOW(KBASE_HWCNT_READER, 0x41, u32)
|
||||
#define KBASE_HWCNT_READER_GET_API_VERSION _IOW(KBASE_HWCNT_READER, 0xFF, u32)
|
||||
|
||||
/**
|
||||
* struct kbase_hwcnt_reader_metadata - hwcnt reader sample buffer metadata
|
||||
* @timestamp: time when sample was collected
|
||||
* @event_id: id of an event that triggered sample collection
|
||||
* @buffer_idx: position in sampling area where sample buffer was stored
|
||||
*/
|
||||
struct kbase_hwcnt_reader_metadata {
|
||||
u64 timestamp;
|
||||
u32 event_id;
|
||||
u32 buffer_idx;
|
||||
};
|
||||
|
||||
/**
|
||||
* enum base_hwcnt_reader_event - hwcnt dumping events
|
||||
* @BASE_HWCNT_READER_EVENT_MANUAL: manual request for dump
|
||||
* @BASE_HWCNT_READER_EVENT_PERIODIC: periodic dump
|
||||
* @BASE_HWCNT_READER_EVENT_PREJOB: prejob dump request
|
||||
* @BASE_HWCNT_READER_EVENT_POSTJOB: postjob dump request
|
||||
* @BASE_HWCNT_READER_EVENT_COUNT: number of supported events
|
||||
*/
|
||||
enum base_hwcnt_reader_event {
|
||||
BASE_HWCNT_READER_EVENT_MANUAL,
|
||||
BASE_HWCNT_READER_EVENT_PERIODIC,
|
||||
BASE_HWCNT_READER_EVENT_PREJOB,
|
||||
BASE_HWCNT_READER_EVENT_POSTJOB,
|
||||
|
||||
BASE_HWCNT_READER_EVENT_COUNT
|
||||
};
|
||||
|
||||
#endif /* _KBASE_HWCNT_READER_H_ */
|
||||
|
||||
137
drivers/gpu/arm/t72x/r7p0/mali_kbase_instr.c
Normal file
137
drivers/gpu/arm/t72x/r7p0/mali_kbase_instr.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
*
|
||||
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
|
||||
*
|
||||
* This program is free software and is provided to you under the terms of the
|
||||
* GNU General Public License version 2 as published by the Free Software
|
||||
* Foundation, and any use by you of this program is subject to the terms
|
||||
* of such GNU licence.
|
||||
*
|
||||
* A copy of the licence is included with the program, and can also be obtained
|
||||
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Base kernel instrumentation APIs.
|
||||
*/
|
||||
|
||||
#include <mali_kbase.h>
|
||||
#include <mali_midg_regmap.h>
|
||||
|
||||
void kbase_instr_hwcnt_suspend(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_context *kctx;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev);
|
||||
KBASE_DEBUG_ASSERT(!kbdev->hwcnt.suspended_kctx);
|
||||
|
||||
kctx = kbdev->hwcnt.kctx;
|
||||
kbdev->hwcnt.suspended_kctx = kctx;
|
||||
|
||||
/* Relevant state was saved into hwcnt.suspended_state when enabling the
|
||||
* counters */
|
||||
|
||||
if (kctx) {
|
||||
KBASE_DEBUG_ASSERT(kctx->jctx.sched_info.ctx.flags &
|
||||
KBASE_CTX_FLAG_PRIVILEGED);
|
||||
kbase_instr_hwcnt_disable(kctx);
|
||||
}
|
||||
}
|
||||
|
||||
void kbase_instr_hwcnt_resume(struct kbase_device *kbdev)
|
||||
{
|
||||
struct kbase_context *kctx;
|
||||
|
||||
KBASE_DEBUG_ASSERT(kbdev);
|
||||
|
||||
kctx = kbdev->hwcnt.suspended_kctx;
|
||||
kbdev->hwcnt.suspended_kctx = NULL;
|
||||
|
||||
if (kctx) {
|
||||
int err;
|
||||
|
||||
err = kbase_instr_hwcnt_enable_internal(kbdev, kctx,
|
||||
&kbdev->hwcnt.suspended_state);
|
||||
WARN(err, "Failed to restore instrumented hardware counters on resume\n");
|
||||
}
|
||||
}
|
||||
|
||||
int kbase_instr_hwcnt_enable(struct kbase_context *kctx,
|
||||
struct kbase_uk_hwcnt_setup *setup)
|
||||
{
|
||||
struct kbase_device *kbdev;
|
||||
bool access_allowed;
|
||||
int err;
|
||||
|
||||
kbdev = kctx->kbdev;
|
||||
|
||||
/* Determine if the calling task has access to this capability */
|
||||
access_allowed = kbase_security_has_capability(kctx,
|
||||
KBASE_SEC_INSTR_HW_COUNTERS_COLLECT,
|
||||
KBASE_SEC_FLAG_NOAUDIT);
|
||||
if (!access_allowed)
|
||||
return -EINVAL;
|
||||
|
||||
/* Mark the context as active so the GPU is kept turned on */
|
||||
/* A suspend won't happen here, because we're in a syscall from a
|
||||
* userspace thread. */
|
||||
kbase_pm_context_active(kbdev);
|
||||
|
||||
/* Schedule the context in */
|
||||
kbasep_js_schedule_privileged_ctx(kbdev, kctx);
|
||||
err = kbase_instr_hwcnt_enable_internal(kbdev, kctx, setup);
|
||||
if (err) {
|
||||
/* Release the context. This had its own Power Manager Active
|
||||
* reference */
|
||||
kbasep_js_release_privileged_ctx(kbdev, kctx);
|
||||
|
||||
/* Also release our Power Manager Active reference */
|
||||
kbase_pm_context_idle(kbdev);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_enable);
|
||||
|
||||
int kbase_instr_hwcnt_disable(struct kbase_context *kctx)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct kbase_device *kbdev = kctx->kbdev;
|
||||
|
||||
err = kbase_instr_hwcnt_disable_internal(kctx);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Release the context. This had its own Power Manager Active reference
|
||||
*/
|
||||
kbasep_js_release_privileged_ctx(kbdev, kctx);
|
||||
|
||||
/* Also release our Power Manager Active reference */
|
||||
kbase_pm_context_idle(kbdev);
|
||||
|
||||
dev_dbg(kbdev->dev, "HW counters dumping disabled for context %p",
|
||||
kctx);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_disable);
|
||||
|
||||
int kbase_instr_hwcnt_dump(struct kbase_context *kctx)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = kbase_instr_hwcnt_request_dump(kctx);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = kbase_instr_hwcnt_wait_for_dump(kctx);
|
||||
return err;
|
||||
}
|
||||
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_dump);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue