MALI: rockchip: upgrade bifrost DDK to r25p1-01bet0, from r21p0-01rel0

In addition, rename some configs that have been used in drivers/gpu/arm/midgard.

Change-Id: I4244ea3ac7f039f182d5e58f677d9c31417188bf
Signed-off-by: Zhen Chen <chenzhen@rock-chips.com>
This commit is contained in:
Zhen Chen 2020-08-18 18:20:15 +08:00 committed by Tao Huang
parent 83297698a1
commit 6017dfa725
161 changed files with 18688 additions and 11121 deletions

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2013-2019 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2013-2020 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -19,13 +19,14 @@
#
#
* ARM Mali Midgard devices
* ARM Mali Midgard / Bifrost devices
Required properties:
- compatible : Should be mali<chip>, replacing digits with x from the back,
until malit<Major>xx, ending with arm,mali-midgard, the latter not optional.
until malit<Major>xx, and it must end with one of: "arm,malit6xx" or
"arm,mali-midgard" or "arm,mali-bifrost"
- reg : Physical base address of the device and length of the register area.
- interrupts : Contains the three IRQ lines required by T-6xx devices
- interrupt-names : Contains the names of IRQ resources in the order they were
@ -107,13 +108,22 @@ for details.
model is not found in the registered models list. If no model is specified here,
a gpu-id based model is picked if available, otherwise the default model is used.
- mali-simple-power-model: Default model used on mali
- protected-mode-switcher : Phandle to device implemented protected mode switching functionality.
Refer to Documentation/devicetree/bindings/arm/smc-protected-mode-switcher.txt for one implementation.
- idvs-group-size : Override the IDVS group size value. Tasks are sent to
cores in groups of N + 1, so i.e. 0xF means 16 tasks.
Valid values are between 0 to 0x3F (including).
- l2-size : Override L2 cache size on GPU that supports it
- l2-hash : Override L2 hash function on GPU that supports it
- arbiter_if : Phandle to the arbif platform device, used to provide KBASE with an interface
to the Arbiter. This is required when using arbitration; setting to a non-NULL
value will enable arbitration.
If arbitration is in use, then there should be no external GPU control.
When arbiter_if is in use then the following must not be:
- power_model (no IPA allowed with arbitration)
- #cooling-cells
- operating-points-v2 (no dvfs in kbase with arbitration)
- system-coherency with a value of 1 (no full coherency with arbitration)
Example for a Mali GPU with 1 clock and no regulators:

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2012-2018 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2012-2020 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -20,9 +20,12 @@
#
# Driver version string which is returned to userspace via an ioctl
MALI_RELEASE_NAME ?= "r21p0-01rel0"
MALI_RELEASE_NAME ?= "r25p1-01bet0"
# Paths required for build
# make $(src) as absolute path if it isn't already, by prefixing $(srctree)
src:=$(if $(patsubst /%,,$(src)),$(srctree)/$(src),$(src))
KBASE_PATH = $(src)
KBASE_PLATFORM_PATH = $(KBASE_PATH)/platform_dummy
UMP_PATH = $(src)/../../../base
@ -34,6 +37,14 @@ MALI_UNIT_TEST ?= 0
MALI_KERNEL_TEST_API ?= 0
MALI_COVERAGE ?= 0
CONFIG_MALI_PLATFORM_NAME ?= "devicetree"
# Experimental features (corresponding -D definition should be appended to
# DEFINES below, e.g. for MALI_EXPERIMENTAL_FEATURE,
# -DMALI_EXPERIMENTAL_FEATURE=$(MALI_EXPERIMENTAL_FEATURE) should be appended)
#
# Experimental features must default to disabled, e.g.:
# MALI_EXPERIMENTAL_FEATURE ?= 0
MALI_JIT_PRESSURE_LIMIT ?= 0
MALI_INCREMENTAL_RENDERING ?= 0
# Set up our defines, which will be passed to gcc
DEFINES = \
@ -42,7 +53,9 @@ DEFINES = \
-DMALI_KERNEL_TEST_API=$(MALI_KERNEL_TEST_API) \
-DMALI_UNIT_TEST=$(MALI_UNIT_TEST) \
-DMALI_COVERAGE=$(MALI_COVERAGE) \
-DMALI_RELEASE_NAME=\"$(MALI_RELEASE_NAME)\"
-DMALI_RELEASE_NAME=\"$(MALI_RELEASE_NAME)\" \
-DMALI_JIT_PRESSURE_LIMIT=$(MALI_JIT_PRESSURE_LIMIT) \
-DMALI_INCREMENTAL_RENDERING=$(MALI_INCREMENTAL_RENDERING)
ifeq ($(KBUILD_EXTMOD),)
# in-tree
@ -61,21 +74,16 @@ ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(UMP_PATH)
subdir-ccflags-y += $(DEFINES) -I$(KBASE_PATH) -I$(KBASE_PLATFORM_PATH) -I$(UMP_PATH) -I$(srctree)/include/linux
SRC := \
mali_kbase_device.c \
context/mali_kbase_context.c \
debug/mali_kbase_debug_ktrace.c \
device/mali_kbase_device.c \
mali_kbase_cache_policy.c \
mali_kbase_mem.c \
mali_kbase_mem_pool_group.c \
mali_kbase_mmu.c \
mali_kbase_native_mgm.c \
mali_kbase_ctx_sched.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_vinstr.c \
@ -86,38 +94,63 @@ SRC := \
mali_kbase_hwcnt_types.c \
mali_kbase_hwcnt_virtualizer.c \
mali_kbase_softjobs.c \
mali_kbase_10969_workaround.c \
mali_kbase_hw.c \
mali_kbase_debug.c \
mali_kbase_gpu_memory_debugfs.c \
mali_kbase_mem_linux.c \
mali_kbase_core_linux.c \
mali_kbase_mem_profile_debugfs.c \
mali_kbase_mmu_mode_lpae.c \
mali_kbase_mmu_mode_aarch64.c \
mmu/mali_kbase_mmu.c \
mmu/mali_kbase_mmu_hw_direct.c \
mmu/mali_kbase_mmu_mode_lpae.c \
mmu/mali_kbase_mmu_mode_aarch64.c \
mali_kbase_disjoint_events.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 \
mali_kbase_debugfs_helper.c \
mali_kbase_timeline.c \
mali_kbase_timeline_io.c \
mali_kbase_tlstream.c \
mali_kbase_tracepoints.c \
mali_kbase_strings.c \
mali_kbase_as_fault_debugfs.c \
mali_kbase_regs_history_debugfs.c \
thirdparty/mali_kbase_mmap.c
thirdparty/mali_kbase_mmap.c \
tl/mali_kbase_timeline.c \
tl/mali_kbase_timeline_io.c \
tl/mali_kbase_tlstream.c \
tl/mali_kbase_tracepoints.c \
gpu/mali_kbase_gpu.c
ifeq ($(MALI_USE_CSF),1)
SRC += \
debug/backend/mali_kbase_debug_ktrace_csf.c \
device/backend/mali_kbase_device_csf.c \
gpu/backend/mali_kbase_gpu_fault_csf.c \
tl/backend/mali_kbase_timeline_csf.c \
mmu/backend/mali_kbase_mmu_csf.c \
context/backend/mali_kbase_context_csf.c
else
SRC += \
mali_kbase_dummy_job_wa.c \
mali_kbase_debug_job_fault.c \
mali_kbase_event.c \
mali_kbase_jd.c \
mali_kbase_jd_debugfs.c \
mali_kbase_js.c \
mali_kbase_js_ctx_attr.c \
debug/backend/mali_kbase_debug_ktrace_jm.c \
device/backend/mali_kbase_device_jm.c \
gpu/backend/mali_kbase_gpu_fault_jm.c \
tl/backend/mali_kbase_timeline_jm.c \
mmu/backend/mali_kbase_mmu_jm.c \
context/backend/mali_kbase_context_jm.c
endif
ifeq ($(CONFIG_MALI_CINSTR_GWT),y)
SRC += mali_kbase_gwt.c
endif
ifeq ($(MALI_UNIT_TEST),1)
SRC += mali_kbase_timeline_test.c
SRC += tl/mali_kbase_timeline_test.c
endif
ifeq ($(MALI_CUSTOMER_RELEASE),0)
@ -125,7 +158,8 @@ ifeq ($(MALI_CUSTOMER_RELEASE),0)
endif
ccflags-y += -I$(KBASE_PATH)
ccflags-y += -I$(KBASE_PATH) -I$(KBASE_PATH)/debug \
-I$(KBASE_PATH)/debug/backend
# Tell the Linux build system from which .o file to create the kernel module
obj-$(CONFIG_MALI_BIFROST) += bifrost_kbase.o
@ -147,6 +181,14 @@ endif
ifeq ($(MALI_USE_CSF),1)
include $(src)/csf/Kbuild
else
# empty
endif
ifeq ($(CONFIG_MALI_ARBITER_SUPPORT),y)
include $(src)/arbiter/Kbuild
else
# empty
endif
bifrost_kbase-$(CONFIG_MALI_BIFROST_DMA_FENCE) += \

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2012-2019 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2012-2020 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -49,6 +49,7 @@ config MALI_BIFROST_DVFS
config MALI_BIFROST_ENABLE_TRACE
bool "Enable kbase tracing"
depends on MALI_BIFROST
default y if MALI_BIFROST_DEBUG
default n
help
Enables tracing in kbase. Trace log available through
@ -83,6 +84,17 @@ config MALI_PLATFORM_NAME
include in the build. 'platform/$(MALI_PLATFORM_NAME)/Kbuild' must
exist.
config MALI_ARBITER_SUPPORT
bool "Enable arbiter support for Mali"
depends on MALI_BIFROST
default n
help
Enable support for the arbiter interface in the driver.
This allows an external arbiter to manage driver access
to GPU hardware in a virtualized environment
If unsure, say N.
# MALI_BIFROST_EXPERT configuration options
menuconfig MALI_BIFROST_EXPERT
@ -155,6 +167,7 @@ config MALI_BIFROST_ERROR_INJECT
config MALI_BIFROST_SYSTEM_TRACE
bool "Enable system event tracing support"
depends on MALI_BIFROST && MALI_BIFROST_EXPERT
default y if MALI_BIFROST_DEBUG
default n
help
Choose this option to enable system trace events for each
@ -209,13 +222,17 @@ config MALI_DMA_BUF_MAP_ON_DEMAND
config MALI_DMA_BUF_LEGACY_COMPAT
bool "Enable legacy compatibility cache flush on dma-buf map"
depends on MALI_BIFROST && !MALI_DMA_BUF_MAP_ON_DEMAND
default y
default n
help
This option enables compatibility with legacy dma-buf mapping
behavior, then the dma-buf is mapped on import, by adding cache
maintenance where MALI_DMA_BUF_MAP_ON_DEMAND would do the mapping,
including a cache flush.
This option might work-around issues related to missing cache
flushes in other drivers. This only has an effect for clients using
UK 11.18 or older. For later UK versions it is not possible.
config MALI_HW_ERRATA_1485982_NOT_AFFECTED
bool "Disable workaround for BASE_HW_ISSUE_GPU2017_1336"
depends on MALI_BIFROST && MALI_BIFROST_EXPERT
@ -239,6 +256,14 @@ config MALI_HW_ERRATA_1485982_USE_CLOCK_ALTERNATIVE
tree using the property, opp-mali-errata-1485982. Otherwise the
slowest clock will be selected.
config MALI_GEM5_BUILD
bool "Enable build of Mali kernel driver for GEM5"
depends on MALI_BIFROST
default n
help
This option is to do a Mali GEM5 build.
If unsure, say N.
# Instrumentation options.
config MALI_JOB_DUMP
@ -264,5 +289,20 @@ config MALI_BIFROST_PRFCNT_SET_SECONDARY
If unsure, say N.
config MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS
bool "Use secondary set of performance counters"
depends on MALI_BIFROST && MALI_BIFROST_EXPERT && !MALI_BIFROST_PRFCNT_SET_SECONDARY && DEBUG_FS
default n
help
Select this option to make the secondary set of performance counters
available at runtime via debugfs. Kernel features that depend on an
access to the primary set of counters may become unavailable.
This feature is unsupported and unstable, and may break at any time.
Enabling this option will prevent power management from working
optimally and may cause instrumentation tools to return bogus results.
If unsure, say N.
source "drivers/gpu/arm/midgard/platform/Kconfig"
# source "drivers/gpu/arm/midgard/tests/Kconfig"

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2012-2019 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2012-2020 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -39,7 +39,7 @@ config MALI_BIFROST_DVFS
config MALI_BIFROST_ENABLE_TRACE
bool "Enable kbase tracing"
depends on MALI_BIFROST
default y if MALI_BIFROST_DEBUG
default n
help
Enables tracing in kbase. Trace log available through
@ -81,6 +81,17 @@ config MALI_PLATFORM_NAME
When PLATFORM_CUSTOM is set, this needs to be set manually to
pick up the desired platform files.
config MALI_ARBITER_SUPPORT
bool "Enable arbiter support for Mali"
depends on MALI_BIFROST
default n
help
Enable support for the arbiter interface in the driver.
This allows an external arbiter to manage driver access
to GPU hardware in a virtualized environment
If unsure, say N.
# MALI_BIFROST_EXPERT configuration options
menuconfig MALI_BIFROST_EXPERT
@ -167,10 +178,11 @@ config MALI_BIFROST_ERROR_INJECT
config MALI_BIFROST_SYSTEM_TRACE
bool "Enable system event tracing support"
depends on MALI_BIFROST && MALI_BIFROST_EXPERT
default y if MALI_BIFROST_DEBUG
default n
help
Choose this option to enable system trace events for each
kbase event. This is typically used for debugging but has
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.
@ -213,7 +225,7 @@ config MALI_DMA_BUF_MAP_ON_DEMAND
config MALI_DMA_BUF_LEGACY_COMPAT
bool "Enable legacy compatibility cache flush on dma-buf map"
depends on MALI_BIFROST && !MALI_DMA_BUF_MAP_ON_DEMAND
default y
default n
help
This option enables compatibility with legacy dma-buf mapping
behavior, then the dma-buf is mapped on import, by adding cache
@ -249,6 +261,14 @@ config MALI_HW_ERRATA_1485982_USE_CLOCK_ALTERNATIVE
tree using the property, opp-mali-errata-1485982. Otherwise the
slowest clock will be selected.
config MALI_GEM5_BUILD
bool "Enable build of Mali kernel driver for GEM5"
depends on MALI_BIFROST
default n
help
This option is to do a Mali GEM5 build.
If unsure, say N.
# Instrumentation options.
# config MALI_JOB_DUMP exists in the Kernel Kconfig but is configured using CINSTR_JOB_DUMP in Mconfig.

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2012-2017, 2019 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -20,5 +20,5 @@
#
mali_kbase-y += \
$(MALI_PLATFORM_DIR)/mali_kbase_config_meson.o \
$(MALI_PLATFORM_DIR)/mali_kbase_runtime_pm.o
arbiter/mali_kbase_arbif.o \
arbiter/mali_kbase_arbiter_pm.o

View File

@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/**
* @file mali_kbase_arbif.c
* Mali arbiter interface APIs to share GPU between Virtual Machines
*/
#include <mali_kbase.h>
#include "mali_kbase_arbif.h"
#include <tl/mali_kbase_tracepoints.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include "mali_kbase_arbiter_interface.h"
static void on_gpu_stop(struct device *dev)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
KBASE_TLSTREAM_TL_EVENT_ARB_STOP_REQUESTED(kbdev, kbdev);
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_STOP_EVT);
}
static void on_gpu_granted(struct device *dev)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
KBASE_TLSTREAM_TL_EVENT_ARB_GRANTED(kbdev, kbdev);
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_GRANTED_EVT);
}
static void on_gpu_lost(struct device *dev)
{
struct kbase_device *kbdev = dev_get_drvdata(dev);
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_LOST_EVT);
}
int kbase_arbif_init(struct kbase_device *kbdev)
{
#ifdef CONFIG_OF
struct arbiter_if_arb_vm_ops ops;
struct arbiter_if_dev *arb_if;
struct device_node *arbiter_if_node;
struct platform_device *pdev;
int err;
dev_dbg(kbdev->dev, "%s\n", __func__);
arbiter_if_node = of_parse_phandle(kbdev->dev->of_node,
"arbiter_if", 0);
if (!arbiter_if_node) {
dev_dbg(kbdev->dev, "No arbiter_if in Device Tree\n");
/* no arbiter interface defined in device tree */
kbdev->arb.arb_dev = NULL;
kbdev->arb.arb_if = NULL;
return 0;
}
pdev = of_find_device_by_node(arbiter_if_node);
if (!pdev) {
dev_err(kbdev->dev, "Failed to find arbiter_if device\n");
return -EPROBE_DEFER;
}
if (!pdev->dev.driver || !try_module_get(pdev->dev.driver->owner)) {
dev_err(kbdev->dev, "arbiter_if driver not available\n");
return -EPROBE_DEFER;
}
kbdev->arb.arb_dev = &pdev->dev;
arb_if = platform_get_drvdata(pdev);
if (!arb_if) {
dev_err(kbdev->dev, "arbiter_if driver not ready\n");
module_put(pdev->dev.driver->owner);
return -EPROBE_DEFER;
}
kbdev->arb.arb_if = arb_if;
ops.arb_vm_gpu_stop = on_gpu_stop;
ops.arb_vm_gpu_granted = on_gpu_granted;
ops.arb_vm_gpu_lost = on_gpu_lost;
/* register kbase arbiter_if callbacks */
if (arb_if->vm_ops.vm_arb_register_dev) {
err = arb_if->vm_ops.vm_arb_register_dev(arb_if,
kbdev->dev, &ops);
if (err) {
dev_err(kbdev->dev, "Arbiter registration failed.\n");
module_put(pdev->dev.driver->owner);
return err;
}
}
#else /* CONFIG_OF */
dev_dbg(kbdev->dev, "No arbiter without Device Tree support\n");
kbdev->arb.arb_dev = NULL;
kbdev->arb.arb_if = NULL;
#endif
return 0;
}
void kbase_arbif_destroy(struct kbase_device *kbdev)
{
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
if (arb_if && arb_if->vm_ops.vm_arb_unregister_dev) {
dev_dbg(kbdev->dev, "%s\n", __func__);
arb_if->vm_ops.vm_arb_unregister_dev(kbdev->arb.arb_if);
}
kbdev->arb.arb_if = NULL;
if (kbdev->arb.arb_dev)
module_put(kbdev->arb.arb_dev->driver->owner);
kbdev->arb.arb_dev = NULL;
}
void kbase_arbif_gpu_request(struct kbase_device *kbdev)
{
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
if (arb_if && arb_if->vm_ops.vm_arb_gpu_request) {
dev_dbg(kbdev->dev, "%s\n", __func__);
arb_if->vm_ops.vm_arb_gpu_request(arb_if);
}
}
void kbase_arbif_gpu_stopped(struct kbase_device *kbdev, u8 gpu_required)
{
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
if (arb_if && arb_if->vm_ops.vm_arb_gpu_stopped) {
dev_dbg(kbdev->dev, "%s\n", __func__);
KBASE_TLSTREAM_TL_EVENT_ARB_STOPPED(kbdev, kbdev);
arb_if->vm_ops.vm_arb_gpu_stopped(arb_if, gpu_required);
}
}
void kbase_arbif_gpu_active(struct kbase_device *kbdev)
{
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
if (arb_if && arb_if->vm_ops.vm_arb_gpu_active) {
dev_dbg(kbdev->dev, "%s\n", __func__);
arb_if->vm_ops.vm_arb_gpu_active(arb_if);
}
}
void kbase_arbif_gpu_idle(struct kbase_device *kbdev)
{
struct arbiter_if_dev *arb_if = kbdev->arb.arb_if;
if (arb_if && arb_if->vm_ops.vm_arb_gpu_idle) {
dev_dbg(kbdev->dev, "vm_arb_gpu_idle\n");
arb_if->vm_ops.vm_arb_gpu_idle(arb_if);
}
}

View File

@ -0,0 +1,133 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
*
*/
/**
* @file
* Mali arbiter interface APIs to share GPU between Virtual Machines
*/
#ifndef _MALI_KBASE_ARBIF_H_
#define _MALI_KBASE_ARBIF_H_
/**
* enum kbase_arbif_evt - Internal Arbiter event.
*
* @KBASE_VM_GPU_INITIALIZED_EVT: KBase has finished initializing
* and can be stopped
* @KBASE_VM_GPU_STOP_EVT: Stop message received from Arbiter
* @KBASE_VM_GPU_GRANTED_EVT: Grant message received from Arbiter
* @KBASE_VM_GPU_LOST_EVT: Lost message received from Arbiter
* @KBASE_VM_GPU_IDLE_EVENT: KBase has transitioned into an inactive state.
* @KBASE_VM_REF_EVENT: KBase has transitioned into an active state.
* @KBASE_VM_OS_SUSPEND_EVENT: KBase is suspending
* @KBASE_VM_OS_RESUME_EVENT: Kbase is resuming
*/
enum kbase_arbif_evt {
KBASE_VM_GPU_INITIALIZED_EVT = 1,
KBASE_VM_GPU_STOP_EVT,
KBASE_VM_GPU_GRANTED_EVT,
KBASE_VM_GPU_LOST_EVT,
KBASE_VM_GPU_IDLE_EVENT,
KBASE_VM_REF_EVENT,
KBASE_VM_OS_SUSPEND_EVENT,
KBASE_VM_OS_RESUME_EVENT,
};
/**
* kbase_arbif_init() - Initialize the arbiter interface functionality.
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Initialize the arbiter interface and also determines
* if Arbiter functionality is required.
*
* Return: 0 if the Arbiter interface was successfully initialized or the
* Arbiter was not required.
*/
int kbase_arbif_init(struct kbase_device *kbdev);
/**
* kbase_arbif_destroy() - Cleanups the arbiter interface functionality.
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Cleans up the arbiter interface functionality and resets the reference count
* of the arbif module used
*/
void kbase_arbif_destroy(struct kbase_device *kbdev);
/**
* kbase_arbif_gpu_request() - Send GPU request message to the arbiter
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Sends a message to Arbiter to request GPU access.
*/
void kbase_arbif_gpu_request(struct kbase_device *kbdev);
/**
* kbase_arbif_gpu_stopped() - Send GPU stopped message to the arbiter
* @kbdev: The kbase device structure for the device (must be a valid pointer)
* @gpu_required: true if GPU access is still required
* (Arbiter will automatically send another grant message)
*
* Sends a message to Arbiter to notify that the GPU has stopped.
* @note Once this call has been made, KBase must not attempt to access the GPU
* until the #KBASE_VM_GPU_GRANTED_EVT event has been received.
*/
void kbase_arbif_gpu_stopped(struct kbase_device *kbdev, u8 gpu_required);
/**
* kbase_arbif_gpu_active() - Send a GPU active message to the arbiter
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Sends a message to Arbiter to report that KBase has gone active.
*/
void kbase_arbif_gpu_active(struct kbase_device *kbdev);
/**
* kbase_arbif_gpu_idle() - Send a GPU idle message to the arbiter
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Sends a message to Arbiter to report that KBase has gone idle.
*/
void kbase_arbif_gpu_idle(struct kbase_device *kbdev);
#endif /* _MALI_KBASE_ARBIF_H_ */

View File

@ -0,0 +1,95 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
*
*/
/**
* @file
* Mali structures define to support arbitration feature
*/
#ifndef _MALI_KBASE_ARBITER_DEFS_H_
#define _MALI_KBASE_ARBITER_DEFS_H_
#include "mali_kbase_arbiter_pm.h"
/**
* struct kbase_arbiter_vm_state - Struct representing the state and containing the
* data of pm work
* @kbdev: Pointer to kbase device structure (must be a valid pointer)
* @vm_state_lock: The lock protecting the VM state when arbiter is used.
* This lock must also be held whenever the VM state is being
* transitioned
* @vm_state_wait: Wait queue set when GPU is granted
* @vm_state: Current state of VM
* @vm_arb_wq: Work queue for resuming or stopping work on the GPU for use
* with the Arbiter
* @vm_suspend_work: Work item for vm_arb_wq to stop current work on GPU
* @vm_resume_work: Work item for vm_arb_wq to resume current work on GPU
* @vm_arb_starting: Work queue resume in progress
* @vm_arb_stopping: Work queue suspend in progress
* @vm_arb_users_waiting: Count of users waiting for GPU
*/
struct kbase_arbiter_vm_state {
struct kbase_device *kbdev;
struct mutex vm_state_lock;
wait_queue_head_t vm_state_wait;
enum kbase_vm_state vm_state;
struct workqueue_struct *vm_arb_wq;
struct work_struct vm_suspend_work;
struct work_struct vm_resume_work;
bool vm_arb_starting;
bool vm_arb_stopping;
int vm_arb_users_waiting;
};
/**
* struct kbase_arbiter_device - Representing an instance of arbiter device,
* allocated from the probe method of Mali driver
* @arb_if: Pointer to the arbiter interface device
* @arb_dev: Pointer to the arbiter device
*/
struct kbase_arbiter_device {
struct arbiter_if_dev *arb_if;
struct device *arb_dev;
};
#endif /* _MALI_KBASE_ARBITER_DEFS_H_ */

View File

@ -0,0 +1,181 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
*
*/
/**
* @file
* Defines the Mali arbiter interface
*/
#ifndef _MALI_KBASE_ARBITER_INTERFACE_H_
#define _MALI_KBASE_ARBITER_INTERFACE_H_
/**
* @brief Mali arbiter interface version
*
* This specifies the current version of the configuration interface. Whenever
* the arbiter interface changes, so that integration effort is required, the
* version number will be increased. Each configuration must make an effort
* to check that it implements the correct version.
*
* Version history:
* 1 - Added the Mali arbiter configuration interface.
* 2 - Strip out reference code from header
* 3 - Removed DVFS utilization interface (DVFS moved to arbiter side)
*/
#define MALI_KBASE_ARBITER_INTERFACE_VERSION 3
struct arbiter_if_dev;
/**
* struct arbiter_if_arb_vm_ops - Interface to communicate messages to VM
*
* This struct contains callbacks used to deliver messages
* from the arbiter to the corresponding VM.
*
* Note that calls into these callbacks may have synchronous calls back into
* the arbiter arbiter_if_vm_arb_ops callbacks below.
* For example vm_arb_gpu_stopped() may be called as a side effect of
* arb_vm_gpu_stop() being called here.
*/
struct arbiter_if_arb_vm_ops {
/**
* arb_vm_gpu_stop() - Ask VM to stop using GPU
* @dev: The arbif kernel module device.
*
* Informs KBase to stop using the GPU as soon as possible.
* @Note: Once the driver is no longer using the GPU, a call to
* vm_arb_gpu_stopped is expected by the arbiter.
*/
void (*arb_vm_gpu_stop)(struct device *dev);
/**
* arb_vm_gpu_granted() - GPU has been granted to VM
* @dev: The arbif kernel module device.
*
* Informs KBase that the GPU can now be used by the VM.
*/
void (*arb_vm_gpu_granted)(struct device *dev);
/**
* arb_vm_gpu_lost() - VM has lost the GPU
* @dev: The arbif kernel module device.
*
* This is called if KBase takes too long to respond to the arbiter
* stop request.
* Once this is called, KBase will assume that access to the GPU
* has been lost and will fail all running jobs and reset its
* internal state.
* If successful, will respond with a vm_arb_gpu_stopped message.
*/
void (*arb_vm_gpu_lost)(struct device *dev);
};
/**
* struct arbiter_if_vm_arb_ops - Interface to communicate messages to arbiter
*
* This struct contains callbacks used to request operations
* from the VM to the arbiter
*
* Note that we must not make any synchronous calls back in to the VM
* (via arbiter_if_arb_vm_ops above) in the context of these callbacks.
*/
struct arbiter_if_vm_arb_ops {
/**
* vm_arb_register_dev() - Register VM device driver callbacks.
* @arbif_dev: The arbiter interface we are registering device callbacks
* @dev: The device structure to supply in the callbacks.
* @ops: The callbacks that the device driver supports
* (none are optional).
*/
int (*vm_arb_register_dev)(struct arbiter_if_dev *arbif_dev,
struct device *dev, struct arbiter_if_arb_vm_ops *ops);
/**
* vm_arb_unregister_dev() - Unregister VM device driver callbacks.
* @arbif_dev: The arbiter interface we are unregistering from.
*/
void (*vm_arb_unregister_dev)(struct arbiter_if_dev *arbif_dev);
/**
* vm_arb_gpu_request() - Ask the arbiter interface for GPU access.
* @arbif_dev: The arbiter interface we want to issue the request.
*/
void (*vm_arb_gpu_request)(struct arbiter_if_dev *arbif_dev);
/**
* vm_arb_gpu_active() - Inform arbiter that the driver has gone active
* @arbif_dev: The arbiter interface device.
*/
void (*vm_arb_gpu_active)(struct arbiter_if_dev *arbif_dev);
/**
* vm_arb_gpu_idle() - Inform the arbiter that the driver has gone idle
* @arbif_dev: The arbiter interface device.
*/
void (*vm_arb_gpu_idle)(struct arbiter_if_dev *arbif_dev);
/**
* vm_arb_gpu_stopped() - Inform the arbiter that the driver has stopped
* using the GPU
* @arbif_dev: The arbiter interface device.
* @gpu_required: The GPU is still needed to do more work.
*/
void (*vm_arb_gpu_stopped)(struct arbiter_if_dev *arbif_dev,
u8 gpu_required);
};
/**
* struct arbiter_if_dev - Arbiter Interface
* @vm_ops: Callback functions for connecting KBase with
* arbiter interface device.
* @priv_data: Internal arbif data not used by KBASE.
*
* Arbiter Interface Kernel Module State used for linking KBase
* with an arbiter interface platform device
*/
struct arbiter_if_dev {
struct arbiter_if_vm_arb_ops vm_ops;
void *priv_data;
};
#endif /* _MALI_KBASE_ARBITER_INTERFACE_H_ */

View File

@ -0,0 +1,645 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/**
* @file mali_kbase_arbiter_pm.c
* Mali arbiter power manager state machine and APIs
*/
#include <mali_kbase.h>
#include <mali_kbase_pm.h>
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_irq_internal.h>
#include <mali_kbase_hwcnt_context.h>
#include <mali_kbase_pm_internal.h>
#include <tl/mali_kbase_tracepoints.h>
static void kbase_arbiter_pm_vm_wait_gpu_assignment(struct kbase_device *kbdev);
static inline bool kbase_arbiter_pm_vm_gpu_assigned_lockheld(
struct kbase_device *kbdev);
static inline const char *kbase_arbiter_pm_vm_state_str(
enum kbase_vm_state state)
{
switch (state) {
case KBASE_VM_STATE_INITIALIZING:
return "KBASE_VM_STATE_INITIALIZING";
case KBASE_VM_STATE_INITIALIZING_WITH_GPU:
return "KBASE_VM_STATE_INITIALIZING_WITH_GPU";
case KBASE_VM_STATE_SUSPENDED:
return "KBASE_VM_STATE_SUSPENDED";
case KBASE_VM_STATE_STOPPED:
return "KBASE_VM_STATE_STOPPED";
case KBASE_VM_STATE_STOPPED_GPU_REQUESTED:
return "KBASE_VM_STATE_STOPPED_GPU_REQUESTED";
case KBASE_VM_STATE_STARTING:
return "KBASE_VM_STATE_STARTING";
case KBASE_VM_STATE_IDLE:
return "KBASE_VM_STATE_IDLE";
case KBASE_VM_STATE_ACTIVE:
return "KBASE_VM_STATE_ACTIVE";
case KBASE_VM_STATE_STOPPING_IDLE:
return "KBASE_VM_STATE_STOPPING_IDLE";
case KBASE_VM_STATE_STOPPING_ACTIVE:
return "KBASE_VM_STATE_STOPPING_ACTIVE";
case KBASE_VM_STATE_SUSPEND_PENDING:
return "KBASE_VM_STATE_SUSPEND_PENDING";
case KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT:
return "KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT";
default:
KBASE_DEBUG_ASSERT(false);
return "[UnknownState]";
}
}
static inline const char *kbase_arbiter_pm_vm_event_str(
enum kbase_arbif_evt evt)
{
switch (evt) {
case KBASE_VM_GPU_INITIALIZED_EVT:
return "KBASE_VM_GPU_INITIALIZED_EVT";
case KBASE_VM_GPU_STOP_EVT:
return "KBASE_VM_GPU_STOP_EVT";
case KBASE_VM_GPU_GRANTED_EVT:
return "KBASE_VM_GPU_GRANTED_EVT";
case KBASE_VM_GPU_LOST_EVT:
return "KBASE_VM_GPU_LOST_EVT";
case KBASE_VM_OS_SUSPEND_EVENT:
return "KBASE_VM_OS_SUSPEND_EVENT";
case KBASE_VM_OS_RESUME_EVENT:
return "KBASE_VM_OS_RESUME_EVENT";
case KBASE_VM_GPU_IDLE_EVENT:
return "KBASE_VM_GPU_IDLE_EVENT";
case KBASE_VM_REF_EVENT:
return "KBASE_VM_REF_EVENT";
default:
KBASE_DEBUG_ASSERT(false);
return "[UnknownEvent]";
}
}
static void kbase_arbiter_pm_vm_set_state(struct kbase_device *kbdev,
enum kbase_vm_state new_state)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
dev_dbg(kbdev->dev, "VM set_state %s -> %s",
kbase_arbiter_pm_vm_state_str(arb_vm_state->vm_state),
kbase_arbiter_pm_vm_state_str(new_state));
lockdep_assert_held(&arb_vm_state->vm_state_lock);
arb_vm_state->vm_state = new_state;
wake_up(&arb_vm_state->vm_state_wait);
}
static void kbase_arbiter_pm_suspend_wq(struct work_struct *data)
{
struct kbase_arbiter_vm_state *arb_vm_state = container_of(data,
struct kbase_arbiter_vm_state,
vm_suspend_work);
struct kbase_device *kbdev = arb_vm_state->kbdev;
mutex_lock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, ">%s\n", __func__);
if (arb_vm_state->vm_state == KBASE_VM_STATE_STOPPING_IDLE ||
arb_vm_state->vm_state ==
KBASE_VM_STATE_STOPPING_ACTIVE ||
arb_vm_state->vm_state ==
KBASE_VM_STATE_SUSPEND_PENDING) {
mutex_unlock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, ">kbase_pm_driver_suspend\n");
kbase_pm_driver_suspend(kbdev);
dev_dbg(kbdev->dev, "<kbase_pm_driver_suspend\n");
mutex_lock(&arb_vm_state->vm_state_lock);
}
mutex_unlock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, "<%s\n", __func__);
}
static void kbase_arbiter_pm_resume_wq(struct work_struct *data)
{
struct kbase_arbiter_vm_state *arb_vm_state = container_of(data,
struct kbase_arbiter_vm_state,
vm_resume_work);
struct kbase_device *kbdev = arb_vm_state->kbdev;
mutex_lock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, ">%s\n", __func__);
arb_vm_state->vm_arb_starting = true;
if (arb_vm_state->vm_state == KBASE_VM_STATE_STARTING) {
mutex_unlock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, ">kbase_pm_driver_resume\n");
kbase_pm_driver_resume(kbdev, true);
dev_dbg(kbdev->dev, "<kbase_pm_driver_resume\n");
mutex_lock(&arb_vm_state->vm_state_lock);
} else if (arb_vm_state->vm_state == KBASE_VM_STATE_STOPPING_ACTIVE) {
kbase_arbiter_pm_vm_stopped(kbdev);
}
arb_vm_state->vm_arb_starting = false;
mutex_unlock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, "<%s\n", __func__);
}
int kbase_arbiter_pm_early_init(struct kbase_device *kbdev)
{
int err;
struct kbase_arbiter_vm_state *arb_vm_state = NULL;
arb_vm_state = kmalloc(sizeof(struct kbase_arbiter_vm_state),
GFP_KERNEL);
if (arb_vm_state == NULL)
return -ENOMEM;
arb_vm_state->kbdev = kbdev;
arb_vm_state->vm_state = KBASE_VM_STATE_INITIALIZING;
mutex_init(&arb_vm_state->vm_state_lock);
init_waitqueue_head(&arb_vm_state->vm_state_wait);
arb_vm_state->vm_arb_wq = alloc_ordered_workqueue("kbase_vm_arb_wq",
WQ_HIGHPRI);
if (!arb_vm_state->vm_arb_wq) {
dev_err(kbdev->dev, "Failed to allocate vm_arb workqueue\n");
return -ENOMEM;
}
INIT_WORK(&arb_vm_state->vm_suspend_work, kbase_arbiter_pm_suspend_wq);
INIT_WORK(&arb_vm_state->vm_resume_work, kbase_arbiter_pm_resume_wq);
arb_vm_state->vm_arb_starting = false;
arb_vm_state->vm_arb_users_waiting = 0;
kbdev->pm.arb_vm_state = arb_vm_state;
err = kbase_arbif_init(kbdev);
if (err) {
goto arbif_init_fail;
}
if (kbdev->arb.arb_if) {
kbase_arbif_gpu_request(kbdev);
dev_dbg(kbdev->dev, "Waiting for initial GPU assignment...\n");
wait_event(arb_vm_state->vm_state_wait,
arb_vm_state->vm_state ==
KBASE_VM_STATE_INITIALIZING_WITH_GPU);
dev_dbg(kbdev->dev,
"Waiting for initial GPU assignment - done\n");
}
return 0;
arbif_init_fail:
destroy_workqueue(arb_vm_state->vm_arb_wq);
kfree(arb_vm_state);
kbdev->pm.arb_vm_state = NULL;
return err;
}
void kbase_arbiter_pm_early_term(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
mutex_lock(&arb_vm_state->vm_state_lock);
if (arb_vm_state->vm_state > KBASE_VM_STATE_STOPPED_GPU_REQUESTED)
kbase_arbif_gpu_stopped(kbdev, false);
mutex_unlock(&arb_vm_state->vm_state_lock);
kbase_arbif_destroy(kbdev);
destroy_workqueue(arb_vm_state->vm_arb_wq);
arb_vm_state->vm_arb_wq = NULL;
kfree(kbdev->pm.arb_vm_state);
kbdev->pm.arb_vm_state = NULL;
}
void kbase_arbiter_pm_release_interrupts(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
mutex_lock(&arb_vm_state->vm_state_lock);
if (!kbdev->arb.arb_if ||
arb_vm_state->vm_state >
KBASE_VM_STATE_STOPPED_GPU_REQUESTED)
kbase_release_interrupts(kbdev);
mutex_unlock(&arb_vm_state->vm_state_lock);
}
void kbase_arbiter_pm_vm_stopped(struct kbase_device *kbdev)
{
bool request_gpu = false;
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
if (arb_vm_state->vm_arb_users_waiting > 0 &&
arb_vm_state->vm_state == KBASE_VM_STATE_STOPPING_IDLE)
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_ACTIVE);
dev_dbg(kbdev->dev, "%s %s\n", __func__,
kbase_arbiter_pm_vm_state_str(arb_vm_state->vm_state));
kbase_release_interrupts(kbdev);
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_STOPPING_ACTIVE:
request_gpu = true;
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPED_GPU_REQUESTED);
break;
case KBASE_VM_STATE_STOPPING_IDLE:
kbase_arbiter_pm_vm_set_state(kbdev, KBASE_VM_STATE_STOPPED);
break;
case KBASE_VM_STATE_SUSPEND_PENDING:
kbase_arbiter_pm_vm_set_state(kbdev, KBASE_VM_STATE_SUSPENDED);
break;
default:
dev_warn(kbdev->dev, "unexpected pm_stop VM state %u",
arb_vm_state->vm_state);
break;
}
kbase_arbif_gpu_stopped(kbdev, request_gpu);
}
static void kbase_arbiter_pm_vm_gpu_start(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_INITIALIZING:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_INITIALIZING_WITH_GPU);
break;
case KBASE_VM_STATE_STOPPED_GPU_REQUESTED:
kbase_arbiter_pm_vm_set_state(kbdev, KBASE_VM_STATE_STARTING);
kbase_install_interrupts(kbdev);
queue_work(arb_vm_state->vm_arb_wq,
&arb_vm_state->vm_resume_work);
break;
case KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT:
kbase_arbif_gpu_stopped(kbdev, false);
kbase_arbiter_pm_vm_set_state(kbdev, KBASE_VM_STATE_SUSPENDED);
break;
default:
dev_warn(kbdev->dev,
"GPU_GRANTED when not expected - state %s\n",
kbase_arbiter_pm_vm_state_str(arb_vm_state->vm_state));
break;
}
}
static void kbase_arbiter_pm_vm_gpu_stop(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
if (arb_vm_state->vm_state == KBASE_VM_STATE_INITIALIZING_WITH_GPU) {
mutex_unlock(&arb_vm_state->vm_state_lock);
kbase_arbiter_pm_vm_wait_gpu_assignment(kbdev);
mutex_lock(&arb_vm_state->vm_state_lock);
}
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_IDLE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_IDLE);
queue_work(arb_vm_state->vm_arb_wq,
&arb_vm_state->vm_suspend_work);
break;
case KBASE_VM_STATE_ACTIVE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_ACTIVE);
queue_work(arb_vm_state->vm_arb_wq,
&arb_vm_state->vm_suspend_work);
break;
case KBASE_VM_STATE_STARTING:
dev_dbg(kbdev->dev, "Got GPU_STOP event while STARTING.");
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_ACTIVE);
if (arb_vm_state->vm_arb_starting)
queue_work(arb_vm_state->vm_arb_wq,
&arb_vm_state->vm_suspend_work);
break;
case KBASE_VM_STATE_SUSPEND_PENDING:
/* Suspend finishes with a stop so nothing else to do */
break;
default:
dev_warn(kbdev->dev, "GPU_STOP when not expected - state %s\n",
kbase_arbiter_pm_vm_state_str(arb_vm_state->vm_state));
break;
}
}
static void kbase_gpu_lost(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_STARTING:
case KBASE_VM_STATE_ACTIVE:
case KBASE_VM_STATE_IDLE:
dev_warn(kbdev->dev, "GPU lost in state %s",
kbase_arbiter_pm_vm_state_str(arb_vm_state->vm_state));
kbase_arbiter_pm_vm_gpu_stop(kbdev);
mutex_unlock(&arb_vm_state->vm_state_lock);
kbase_pm_handle_gpu_lost(kbdev);
mutex_lock(&arb_vm_state->vm_state_lock);
break;
case KBASE_VM_STATE_STOPPING_IDLE:
case KBASE_VM_STATE_STOPPING_ACTIVE:
case KBASE_VM_STATE_SUSPEND_PENDING:
dev_info(kbdev->dev, "GPU lost while stopping");
mutex_unlock(&arb_vm_state->vm_state_lock);
kbase_pm_handle_gpu_lost(kbdev);
mutex_lock(&arb_vm_state->vm_state_lock);
break;
case KBASE_VM_STATE_SUSPENDED:
case KBASE_VM_STATE_STOPPED:
case KBASE_VM_STATE_STOPPED_GPU_REQUESTED:
dev_info(kbdev->dev, "GPU lost while already stopped");
break;
case KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT:
dev_info(kbdev->dev, "GPU lost while waiting to suspend");
kbase_arbiter_pm_vm_set_state(kbdev, KBASE_VM_STATE_SUSPENDED);
break;
default:
break;
}
}
static inline bool kbase_arbiter_pm_vm_os_suspend_ready_state(
struct kbase_device *kbdev)
{
switch (kbdev->pm.arb_vm_state->vm_state) {
case KBASE_VM_STATE_SUSPENDED:
case KBASE_VM_STATE_STOPPED:
case KBASE_VM_STATE_IDLE:
case KBASE_VM_STATE_ACTIVE:
return true;
default:
return false;
}
}
static void kbase_arbiter_pm_vm_os_prepare_suspend(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
enum kbase_vm_state prev_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
if (kbdev->arb.arb_if) {
if (kbdev->pm.arb_vm_state->vm_state ==
KBASE_VM_STATE_SUSPENDED)
return;
}
/* Block suspend OS function until we are in a stable state
* with vm_state_lock
*/
while (!kbase_arbiter_pm_vm_os_suspend_ready_state(kbdev)) {
prev_state = arb_vm_state->vm_state;
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_STOPPING_ACTIVE:
case KBASE_VM_STATE_STOPPING_IDLE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_SUSPEND_PENDING);
break;
case KBASE_VM_STATE_STOPPED_GPU_REQUESTED:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT);
break;
case KBASE_VM_STATE_STARTING:
if (!arb_vm_state->vm_arb_starting) {
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_SUSPEND_PENDING);
kbase_arbiter_pm_vm_stopped(kbdev);
}
break;
default:
break;
}
mutex_unlock(&arb_vm_state->vm_state_lock);
wait_event(arb_vm_state->vm_state_wait,
arb_vm_state->vm_state != prev_state);
mutex_lock(&arb_vm_state->vm_state_lock);
}
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_STOPPED:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_SUSPENDED);
break;
case KBASE_VM_STATE_IDLE:
case KBASE_VM_STATE_ACTIVE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_SUSPEND_PENDING);
mutex_unlock(&arb_vm_state->vm_state_lock);
/* Ensure resume has completed fully before starting suspend */
flush_work(&arb_vm_state->vm_resume_work);
kbase_pm_driver_suspend(kbdev);
mutex_lock(&arb_vm_state->vm_state_lock);
break;
case KBASE_VM_STATE_SUSPENDED:
break;
default:
KBASE_DEBUG_ASSERT_MSG(false, "Unexpected state to suspend");
break;
}
}
static void kbase_arbiter_pm_vm_os_resume(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
KBASE_DEBUG_ASSERT_MSG(arb_vm_state->vm_state ==
KBASE_VM_STATE_SUSPENDED,
"Unexpected state to resume");
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPED_GPU_REQUESTED);
kbase_arbif_gpu_request(kbdev);
/* Release lock and block resume OS function until we have
* asynchronously received the GRANT message from the Arbiter and
* fully resumed
*/
mutex_unlock(&arb_vm_state->vm_state_lock);
kbase_arbiter_pm_vm_wait_gpu_assignment(kbdev);
flush_work(&arb_vm_state->vm_resume_work);
mutex_lock(&arb_vm_state->vm_state_lock);
}
void kbase_arbiter_pm_vm_event(struct kbase_device *kbdev,
enum kbase_arbif_evt evt)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
if (!kbdev->arb.arb_if)
return;
mutex_lock(&arb_vm_state->vm_state_lock);
dev_dbg(kbdev->dev, "%s %s\n", __func__,
kbase_arbiter_pm_vm_event_str(evt));
switch (evt) {
case KBASE_VM_GPU_GRANTED_EVT:
kbase_arbiter_pm_vm_gpu_start(kbdev);
break;
case KBASE_VM_GPU_STOP_EVT:
kbase_arbiter_pm_vm_gpu_stop(kbdev);
break;
case KBASE_VM_GPU_LOST_EVT:
dev_info(kbdev->dev, "KBASE_ARBIF_GPU_LOST_EVT!");
kbase_gpu_lost(kbdev);
break;
case KBASE_VM_OS_SUSPEND_EVENT:
kbase_arbiter_pm_vm_os_prepare_suspend(kbdev);
break;
case KBASE_VM_OS_RESUME_EVENT:
kbase_arbiter_pm_vm_os_resume(kbdev);
break;
case KBASE_VM_GPU_IDLE_EVENT:
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_ACTIVE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_IDLE);
kbase_arbif_gpu_idle(kbdev);
break;
default:
break;
}
break;
case KBASE_VM_REF_EVENT:
switch (arb_vm_state->vm_state) {
case KBASE_VM_STATE_STARTING:
KBASE_TLSTREAM_TL_EVENT_ARB_STARTED(kbdev, kbdev);
/* FALL THROUGH */
case KBASE_VM_STATE_IDLE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_ACTIVE);
kbase_arbif_gpu_active(kbdev);
break;
case KBASE_VM_STATE_STOPPING_IDLE:
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_ACTIVE);
break;
default:
break;
}
break;
case KBASE_VM_GPU_INITIALIZED_EVT:
lockdep_assert_held(&kbdev->pm.lock);
if (kbdev->pm.active_count > 0) {
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_ACTIVE);
kbase_arbif_gpu_active(kbdev);
} else {
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_IDLE);
kbase_arbif_gpu_idle(kbdev);
}
break;
default:
dev_alert(kbdev->dev, "Got Unknown Event!");
break;
}
mutex_unlock(&arb_vm_state->vm_state_lock);
}
static void kbase_arbiter_pm_vm_wait_gpu_assignment(struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
dev_dbg(kbdev->dev, "Waiting for GPU assignment...\n");
wait_event(arb_vm_state->vm_state_wait,
arb_vm_state->vm_state == KBASE_VM_STATE_IDLE ||
arb_vm_state->vm_state == KBASE_VM_STATE_ACTIVE);
dev_dbg(kbdev->dev, "Waiting for GPU assignment - done\n");
}
static inline bool kbase_arbiter_pm_vm_gpu_assigned_lockheld(
struct kbase_device *kbdev)
{
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
lockdep_assert_held(&arb_vm_state->vm_state_lock);
return (arb_vm_state->vm_state == KBASE_VM_STATE_IDLE ||
arb_vm_state->vm_state == KBASE_VM_STATE_ACTIVE);
}
int kbase_arbiter_pm_ctx_active_handle_suspend(struct kbase_device *kbdev,
enum kbase_pm_suspend_handler suspend_handler)
{
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
struct kbase_arbiter_vm_state *arb_vm_state = kbdev->pm.arb_vm_state;
if (kbdev->arb.arb_if) {
mutex_lock(&arb_vm_state->vm_state_lock);
while (!kbase_arbiter_pm_vm_gpu_assigned_lockheld(kbdev)) {
/* Update VM state since we have GPU work to do */
if (arb_vm_state->vm_state ==
KBASE_VM_STATE_STOPPING_IDLE)
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPING_ACTIVE);
else if (arb_vm_state->vm_state ==
KBASE_VM_STATE_STOPPED) {
kbase_arbiter_pm_vm_set_state(kbdev,
KBASE_VM_STATE_STOPPED_GPU_REQUESTED);
kbase_arbif_gpu_request(kbdev);
} else if (arb_vm_state->vm_state ==
KBASE_VM_STATE_INITIALIZING_WITH_GPU)
break;
if (suspend_handler !=
KBASE_PM_SUSPEND_HANDLER_NOT_POSSIBLE) {
if (suspend_handler ==
KBASE_PM_SUSPEND_HANDLER_VM_GPU_GRANTED
||
kbdev->pm.active_count > 0)
break;
mutex_unlock(&arb_vm_state->vm_state_lock);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
return 1;
}
if (arb_vm_state->vm_state ==
KBASE_VM_STATE_INITIALIZING_WITH_GPU)
break;
/* Need to synchronously wait for GPU assignment */
arb_vm_state->vm_arb_users_waiting++;
mutex_unlock(&arb_vm_state->vm_state_lock);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_arbiter_pm_vm_wait_gpu_assignment(kbdev);
mutex_lock(&js_devdata->runpool_mutex);
mutex_lock(&kbdev->pm.lock);
mutex_lock(&arb_vm_state->vm_state_lock);
arb_vm_state->vm_arb_users_waiting--;
}
mutex_unlock(&arb_vm_state->vm_state_lock);
}
return 0;
}

View File

@ -0,0 +1,159 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/**
* @file
* Mali arbiter power manager state machine and APIs
*/
#ifndef _MALI_KBASE_ARBITER_PM_H_
#define _MALI_KBASE_ARBITER_PM_H_
#include "mali_kbase_arbif.h"
/**
* enum kbase_vm_state - Current PM Arbitration state.
*
* @KBASE_VM_STATE_INITIALIZING: Special state before arbiter is initialized.
* @KBASE_VM_STATE_INITIALIZING_WITH_GPU: Initialization after GPU
* has been granted.
* @KBASE_VM_STATE_SUSPENDED: KBase is suspended by OS and GPU is not assigned.
* @KBASE_VM_STATE_STOPPED: GPU is not assigned to KBase and is not required.
* @KBASE_VM_STATE_STOPPED_GPU_REQUESTED: GPU is not assigned to KBase
* but a request has been made.
* @KBASE_VM_STATE_STARTING: GPU is assigned and KBase is getting ready to run.
* @KBASE_VM_STATE_IDLE: GPU is assigned but KBase has no work to do
* @KBASE_VM_STATE_ACTIVE: GPU is assigned and KBase is busy using it
* @KBASE_VM_STATE_SUSPEND_PENDING: OS is going into suspend mode.
* @KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT: OS is going into suspend mode but GPU
* has already been requested.
* In this situation we must wait for
* the Arbiter to send a GRANTED message
* and respond immediately with
* a STOPPED message before entering
* the suspend mode.
* @KBASE_VM_STATE_STOPPING_IDLE: Arbiter has sent a stopped message and there
* is currently no work to do on the GPU.
* @KBASE_VM_STATE_STOPPING_ACTIVE: Arbiter has sent a stopped message when
* KBase has work to do.
*/
enum kbase_vm_state {
KBASE_VM_STATE_INITIALIZING,
KBASE_VM_STATE_INITIALIZING_WITH_GPU,
KBASE_VM_STATE_SUSPENDED,
KBASE_VM_STATE_STOPPED,
KBASE_VM_STATE_STOPPED_GPU_REQUESTED,
KBASE_VM_STATE_STARTING,
KBASE_VM_STATE_IDLE,
KBASE_VM_STATE_ACTIVE,
KBASE_VM_STATE_SUSPEND_PENDING,
KBASE_VM_STATE_SUSPEND_WAIT_FOR_GRANT,
KBASE_VM_STATE_STOPPING_IDLE,
KBASE_VM_STATE_STOPPING_ACTIVE
};
/**
* kbase_arbiter_pm_early_init() - Initialize arbiter for VM Paravirtualized use
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Initialize the arbiter and other required resources during the runtime
* and request the GPU for the VM for the first time.
*
* Return: 0 if successful, otherwise a standard Linux error code
*/
int kbase_arbiter_pm_early_init(struct kbase_device *kbdev);
/**
* kbase_arbiter_pm_early_term() - Shutdown arbiter and free resources.
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Clean up all the resources
*/
void kbase_arbiter_pm_early_term(struct kbase_device *kbdev);
/**
* kbase_arbiter_pm_release_interrupts() - Release the GPU interrupts
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Releases interrupts if needed (GPU is available) otherwise does nothing
*/
void kbase_arbiter_pm_release_interrupts(struct kbase_device *kbdev);
/**
* kbase_arbiter_pm_vm_event() - Dispatch VM event to the state machine
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* The state machine function. Receives events and transitions states
* according the event received and the current state
*/
void kbase_arbiter_pm_vm_event(struct kbase_device *kbdev,
enum kbase_arbif_evt event);
/**
* kbase_arbiter_pm_ctx_active_handle_suspend() - Handle suspend operation for
* arbitration mode
* @kbdev: The kbase device structure for the device (must be a valid pointer)
* @suspend_handler: The handler code for how to handle a suspend
* that might occur
*
* This function handles a suspend event from the driver,
* communicating with the arbiter and waiting synchronously for the GPU
* to be granted again depending on the VM state.
*
* Return: 0 if success, 1 if failure due to system suspending/suspended
*/
int kbase_arbiter_pm_ctx_active_handle_suspend(struct kbase_device *kbdev,
enum kbase_pm_suspend_handler suspend_handler);
/**
* kbase_arbiter_pm_vm_stopped() - Handle stop event for the VM
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* This function handles a stop event for the VM.
* It will update the VM state and forward the stop event to the driver.
*/
void kbase_arbiter_pm_vm_stopped(struct kbase_device *kbdev);
#endif /*_MALI_KBASE_ARBITER_PM_H_ */

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
#
# This program is free software and is provided to you under the terms of the
# GNU General Public License version 2 as published by the Free Software
@ -22,16 +22,10 @@
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_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 \
@ -42,6 +36,16 @@ BACKEND += \
backend/gpu/mali_kbase_time.c \
backend/gpu/mali_kbase_l2_mmu_config.c
ifeq ($(MALI_USE_CSF),1)
# empty
else
BACKEND += \
backend/gpu/mali_kbase_jm_as.c \
backend/gpu/mali_kbase_debug_job_fault_backend.c \
backend/gpu/mali_kbase_jm_hw.c \
backend/gpu/mali_kbase_jm_rb.c
endif
ifeq ($(MALI_CUSTOMER_RELEASE),0)
BACKEND += \
backend/gpu/mali_kbase_pm_always_on_demand.c

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2012-2015,2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2012-2015,2018-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -70,6 +70,8 @@ static int mmu_reg_snapshot[] = {
static int as_reg_snapshot[] = {
AS_TRANSTAB_LO,
AS_TRANSTAB_HI,
AS_TRANSCFG_LO,
AS_TRANSCFG_HI,
AS_MEMATTR_LO,
AS_MEMATTR_HI,
AS_FAULTSTATUS,

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -21,7 +21,7 @@
*/
#include <mali_kbase.h>
#include <mali_kbase_tracepoints.h>
#include <tl/mali_kbase_tracepoints.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <linux/of.h>

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2016, 2018-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016, 2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -25,15 +25,15 @@
*
*/
#include <mali_kbase.h>
#include <gpu/mali_kbase_gpu_fault.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>
#include <backend/gpu/mali_kbase_mmu_hw_direct.h>
#include <mali_kbase_reset_gpu.h>
#include <mmu/mali_kbase_mmu.h>
#if !defined(CONFIG_MALI_BIFROST_NO_MALI)
#ifdef CONFIG_DEBUG_FS
int kbase_io_history_resize(struct kbase_io_history *h, u16 new_size)
@ -143,8 +143,8 @@ void kbase_io_history_dump(struct kbase_device *kbdev)
&h->buf[(h->count - iters + i) % h->size];
char const access = (io->addr & 1) ? 'w' : 'r';
dev_err(kbdev->dev, "%6i: %c: reg 0x%p val %08x\n", i, access,
(void *)(io->addr & ~0x1), io->value);
dev_err(kbdev->dev, "%6i: %c: reg 0x%016lx val %08x\n", i,
access, (unsigned long)(io->addr & ~0x1), io->value);
}
spin_unlock_irqrestore(&h->lock, flags);
@ -190,6 +190,15 @@ u32 kbase_reg_read(struct kbase_device *kbdev, u32 offset)
}
KBASE_EXPORT_TEST_API(kbase_reg_read);
bool kbase_is_gpu_lost(struct kbase_device *kbdev)
{
u32 val;
val = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID));
return val == 0;
}
#endif /* !defined(CONFIG_MALI_BIFROST_NO_MALI) */
/**
@ -203,23 +212,19 @@ KBASE_EXPORT_TEST_API(kbase_reg_read);
*/
static void kbase_report_gpu_fault(struct kbase_device *kbdev, int multiple)
{
u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
u32 status = kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_FAULTSTATUS));
u32 status = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_FAULTSTATUS));
u64 address = (u64) kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_FAULTADDRESS_HI)) << 32;
address |= kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_FAULTADDRESS_LO));
if ((gpu_id & GPU_ID2_PRODUCT_MODEL) != GPU_ID2_PRODUCT_TULX) {
dev_warn(kbdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx",
status,
kbase_exception_name(kbdev, status & 0xFF),
address);
if (multiple)
dev_warn(kbdev->dev, "There were multiple GPU faults - some have not been reported\n");
}
dev_warn(kbdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx",
status,
kbase_gpu_exception_name(status & 0xFF),
address);
if (multiple)
dev_warn(kbdev->dev, "There were multiple GPU faults - some have not been reported\n");
}
static bool kbase_gpu_fault_interrupt(struct kbase_device *kbdev, int multiple)
@ -249,7 +254,7 @@ void kbase_gpu_start_cache_clean_nolock(struct kbase_device *kbdev)
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK),
irq_mask | CLEAN_CACHES_COMPLETED);
KBASE_TRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, 0);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CLEAN_INV_CACHES);
@ -284,7 +289,7 @@ static void kbase_clean_caches_done(struct kbase_device *kbdev)
if (kbdev->cache_clean_queued) {
kbdev->cache_clean_queued = false;
KBASE_TRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_CLEAN_INV_CACHES, NULL, 0);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_CLEAN_INV_CACHES);
} else {
@ -299,25 +304,45 @@ static void kbase_clean_caches_done(struct kbase_device *kbdev)
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
void kbase_gpu_wait_cache_clean(struct kbase_device *kbdev)
static inline bool get_cache_clean_flag(struct kbase_device *kbdev)
{
bool cache_clean_in_progress;
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
while (kbdev->cache_clean_in_progress) {
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
cache_clean_in_progress = kbdev->cache_clean_in_progress;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
return cache_clean_in_progress;
}
void kbase_gpu_wait_cache_clean(struct kbase_device *kbdev)
{
while (get_cache_clean_flag(kbdev)) {
wait_event_interruptible(kbdev->cache_clean_wait,
!kbdev->cache_clean_in_progress);
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
}
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
int kbase_gpu_wait_cache_clean_timeout(struct kbase_device *kbdev,
unsigned int wait_timeout_ms)
{
long remaining = msecs_to_jiffies(wait_timeout_ms);
while (remaining && get_cache_clean_flag(kbdev)) {
remaining = wait_event_timeout(kbdev->cache_clean_wait,
!kbdev->cache_clean_in_progress,
remaining);
}
return (remaining ? 0 : -ETIMEDOUT);
}
void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val)
{
bool clear_gpu_fault = false;
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ, NULL, NULL, 0u, val);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ, NULL, val);
if (val & GPU_FAULT)
clear_gpu_fault = kbase_gpu_fault_interrupt(kbdev,
val & MULTIPLE_GPU_FAULTS);
@ -328,7 +353,7 @@ void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val)
if (val & PRFCNT_SAMPLE_COMPLETED)
kbase_instr_hwcnt_sample_done(kbdev);
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, NULL, 0u, val);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_CLEAR, NULL, val);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), val);
/* kbase_pm_check_transitions (called by kbase_pm_power_changed) must
@ -358,5 +383,5 @@ void kbase_gpu_interrupt(struct kbase_device *kbdev, u32 val)
}
KBASE_TRACE_ADD(kbdev, CORE_GPU_IRQ_DONE, NULL, NULL, 0u, val);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_IRQ_DONE, NULL, val);
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014,2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014,2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -50,6 +50,18 @@ void kbase_reg_write(struct kbase_device *kbdev, u32 offset, u32 value);
*/
u32 kbase_reg_read(struct kbase_device *kbdev, u32 offset);
/**
* kbase_is_gpu_lost() - Has the GPU been lost.
* @kbdev: Kbase device pointer
*
* This function will return true if the GPU has been lost.
* When this happens register reads will be zero. A zero GPU_ID is
* invalid so this is used to detect GPU_LOST
*
* Return: True if GPU LOST
*/
bool kbase_is_gpu_lost(struct kbase_device *kbdev);
/**
* kbase_gpu_start_cache_clean - Start a cache clean
* @kbdev: Kbase device
@ -76,6 +88,22 @@ void kbase_gpu_start_cache_clean_nolock(struct kbase_device *kbdev);
*/
void kbase_gpu_wait_cache_clean(struct kbase_device *kbdev);
/**
* kbase_gpu_wait_cache_clean_timeout - Wait for certain time for cache
* cleaning to finish
* @kbdev: Kbase device
* @wait_timeout_ms: Time, in milli seconds, to wait for cache clean to complete.
*
* This function will take hwaccess_lock, and may sleep. This is supposed to be
* called from paths (like GPU reset) where an indefinite wait for the completion
* of cache clean operation can cause deadlock, as the operation may never
* complete.
*
* Return: 0 if successful or a negative error code on failure.
*/
int kbase_gpu_wait_cache_clean_timeout(struct kbase_device *kbdev,
unsigned int wait_timeout_ms);
/**
* kbase_gpu_cache_clean_wait_complete - Called after the cache cleaning is
* finished. Would also be called after

View File

@ -1,162 +0,0 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Register-based HW access backend APIs
*/
#include <mali_kbase.h>
#include <mali_kbase_hwaccess_backend.h>
#include <mali_kbase_reset_gpu.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;
err = kbase_pm_runtime_init(kbdev);
if (err)
goto fail_runtime_pm;
/* 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_install_interrupts(kbdev);
if (err)
goto fail_interrupts;
return 0;
fail_interrupts:
kbase_pm_runtime_term(kbdev);
fail_runtime_pm:
kbasep_platform_device_term(kbdev);
return err;
}
void kbase_backend_early_term(struct kbase_device *kbdev)
{
kbase_release_interrupts(kbdev);
kbase_pm_runtime_term(kbdev);
kbasep_platform_device_term(kbdev);
}
int kbase_backend_late_init(struct kbase_device *kbdev)
{
int err;
err = kbase_hwaccess_pm_init(kbdev);
if (err)
return err;
err = kbase_reset_gpu_init(kbdev);
if (err)
goto fail_reset_gpu_init;
err = kbase_hwaccess_pm_powerup(kbdev, PM_HW_ISSUES_DETECT);
if (err)
goto fail_pm_powerup;
err = kbase_backend_timer_init(kbdev);
if (err)
goto fail_timer;
#ifdef CONFIG_MALI_BIFROST_DEBUG
#ifndef CONFIG_MALI_BIFROST_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_BIFROST_NO_MALI */
#endif /* CONFIG_MALI_BIFROST_DEBUG */
err = kbase_job_slot_init(kbdev);
if (err)
goto fail_job_slot;
/* Do the initialisation of devfreq.
* Devfreq needs backend_timer_init() for completion of its
* initialisation and it also needs to catch the first callback
* occurence of the runtime_suspend event for maintaining state
* coherence with the backend power management, hence needs to be
* placed before the kbase_pm_context_idle().
*/
err = kbase_backend_devfreq_init(kbdev);
if (err)
goto fail_devfreq_init;
/* Idle the GPU and/or cores, if the policy wants it to */
kbase_pm_context_idle(kbdev);
/* Update gpuprops with L2_FEATURES if applicable */
kbase_gpuprops_update_l2_features(kbdev);
init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait);
return 0;
fail_devfreq_init:
kbase_job_slot_term(kbdev);
fail_job_slot:
#ifdef CONFIG_MALI_BIFROST_DEBUG
#ifndef CONFIG_MALI_BIFROST_NO_MALI
fail_interrupt_test:
#endif /* !CONFIG_MALI_BIFROST_NO_MALI */
#endif /* CONFIG_MALI_BIFROST_DEBUG */
kbase_backend_timer_term(kbdev);
fail_timer:
kbase_hwaccess_pm_halt(kbdev);
fail_pm_powerup:
kbase_reset_gpu_term(kbdev);
fail_reset_gpu_init:
kbase_hwaccess_pm_term(kbdev);
return err;
}
void kbase_backend_late_term(struct kbase_device *kbdev)
{
kbase_backend_devfreq_term(kbdev);
kbase_job_slot_halt(kbdev);
kbase_job_slot_term(kbdev);
kbase_backend_timer_term(kbdev);
kbase_hwaccess_pm_halt(kbdev);
kbase_reset_gpu_term(kbdev);
kbase_hwaccess_pm_term(kbdev);
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,8 +21,6 @@
*
*/
/*
* Base kernel property query backend APIs
*/
@ -31,79 +30,93 @@
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <mali_kbase_hwaccess_gpuprops.h>
void kbase_backend_gpuprops_get(struct kbase_device *kbdev,
int kbase_backend_gpuprops_get(struct kbase_device *kbdev,
struct kbase_gpuprops_regdump *regdump)
{
int i;
struct kbase_gpuprops_regdump registers;
/* Fill regdump with the content of the relevant registers */
regdump->gpu_id = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID));
registers.gpu_id = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_ID));
regdump->l2_features = kbase_reg_read(kbdev,
registers.l2_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_FEATURES));
regdump->core_features = kbase_reg_read(kbdev,
registers.core_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(CORE_FEATURES));
regdump->tiler_features = kbase_reg_read(kbdev,
registers.tiler_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_FEATURES));
regdump->mem_features = kbase_reg_read(kbdev,
registers.mem_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(MEM_FEATURES));
regdump->mmu_features = kbase_reg_read(kbdev,
registers.mmu_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(MMU_FEATURES));
regdump->as_present = kbase_reg_read(kbdev,
registers.as_present = kbase_reg_read(kbdev,
GPU_CONTROL_REG(AS_PRESENT));
regdump->js_present = kbase_reg_read(kbdev,
registers.js_present = kbase_reg_read(kbdev,
GPU_CONTROL_REG(JS_PRESENT));
for (i = 0; i < GPU_MAX_JOB_SLOTS; i++)
regdump->js_features[i] = kbase_reg_read(kbdev,
registers.js_features[i] = kbase_reg_read(kbdev,
GPU_CONTROL_REG(JS_FEATURES_REG(i)));
for (i = 0; i < BASE_GPU_NUM_TEXTURE_FEATURES_REGISTERS; i++)
regdump->texture_features[i] = kbase_reg_read(kbdev,
registers.texture_features[i] = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TEXTURE_FEATURES_REG(i)));
regdump->thread_max_threads = kbase_reg_read(kbdev,
registers.thread_max_threads = kbase_reg_read(kbdev,
GPU_CONTROL_REG(THREAD_MAX_THREADS));
regdump->thread_max_workgroup_size = kbase_reg_read(kbdev,
registers.thread_max_workgroup_size = kbase_reg_read(kbdev,
GPU_CONTROL_REG(THREAD_MAX_WORKGROUP_SIZE));
regdump->thread_max_barrier_size = kbase_reg_read(kbdev,
registers.thread_max_barrier_size = kbase_reg_read(kbdev,
GPU_CONTROL_REG(THREAD_MAX_BARRIER_SIZE));
regdump->thread_features = kbase_reg_read(kbdev,
registers.thread_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(THREAD_FEATURES));
regdump->thread_tls_alloc = kbase_reg_read(kbdev,
registers.thread_tls_alloc = kbase_reg_read(kbdev,
GPU_CONTROL_REG(THREAD_TLS_ALLOC));
regdump->shader_present_lo = kbase_reg_read(kbdev,
registers.shader_present_lo = kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_PRESENT_LO));
regdump->shader_present_hi = kbase_reg_read(kbdev,
registers.shader_present_hi = kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_PRESENT_HI));
regdump->tiler_present_lo = kbase_reg_read(kbdev,
registers.tiler_present_lo = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_PRESENT_LO));
regdump->tiler_present_hi = kbase_reg_read(kbdev,
registers.tiler_present_hi = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_PRESENT_HI));
regdump->l2_present_lo = kbase_reg_read(kbdev,
registers.l2_present_lo = kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_PRESENT_LO));
regdump->l2_present_hi = kbase_reg_read(kbdev,
registers.l2_present_hi = kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_PRESENT_HI));
regdump->stack_present_lo = kbase_reg_read(kbdev,
registers.stack_present_lo = kbase_reg_read(kbdev,
GPU_CONTROL_REG(STACK_PRESENT_LO));
regdump->stack_present_hi = kbase_reg_read(kbdev,
registers.stack_present_hi = kbase_reg_read(kbdev,
GPU_CONTROL_REG(STACK_PRESENT_HI));
if (!kbase_is_gpu_lost(kbdev)) {
*regdump = registers;
return 0;
} else
return -EIO;
}
void kbase_backend_gpuprops_get_features(struct kbase_device *kbdev,
int kbase_backend_gpuprops_get_features(struct kbase_device *kbdev,
struct kbase_gpuprops_regdump *regdump)
{
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_COHERENCY_REG)) {
u32 coherency_features;
/* Ensure we can access the GPU registers */
kbase_pm_register_access_enable(kbdev);
regdump->coherency_features = kbase_reg_read(kbdev,
coherency_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(COHERENCY_FEATURES));
if (kbase_is_gpu_lost(kbdev))
return -EIO;
regdump->coherency_features = coherency_features;
/* We're done accessing the GPU registers for now. */
kbase_pm_register_access_disable(kbdev);
} else {
@ -112,14 +125,22 @@ void kbase_backend_gpuprops_get_features(struct kbase_device *kbdev,
COHERENCY_FEATURE_BIT(COHERENCY_NONE) |
COHERENCY_FEATURE_BIT(COHERENCY_ACE_LITE);
}
return 0;
}
void kbase_backend_gpuprops_get_l2_features(struct kbase_device *kbdev,
int kbase_backend_gpuprops_get_l2_features(struct kbase_device *kbdev,
struct kbase_gpuprops_regdump *regdump)
{
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_L2_CONFIG)) {
regdump->l2_features = kbase_reg_read(kbdev,
u32 l2_features = kbase_reg_read(kbdev,
GPU_CONTROL_REG(L2_FEATURES));
}
}
if (kbase_is_gpu_lost(kbdev))
return -EIO;
regdump->l2_features = l2_features;
}
return 0;
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -27,11 +27,12 @@
*/
#include <mali_kbase.h>
#include <mali_midg_regmap.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase_hwaccess_instr.h>
#include <backend/gpu/mali_kbase_device_internal.h>
#include <backend/gpu/mali_kbase_instr_internal.h>
int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev,
struct kbase_context *kctx,
struct kbase_instr_hwcnt_enable *enable)
@ -70,7 +71,11 @@ int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev,
/* Configure */
prfcnt_config = kctx->as_nr << PRFCNT_CONFIG_AS_SHIFT;
#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS
if (kbdev->hwcnt.backend.use_secondary_override)
#else
if (enable->use_secondary)
#endif
prfcnt_config |= 1 << PRFCNT_CONFIG_SETSELECT_SHIFT;
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG),
@ -80,16 +85,17 @@ int kbase_instr_hwcnt_enable_internal(struct kbase_device *kbdev,
enable->dump_buffer & 0xFFFFFFFF);
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_BASE_HI),
enable->dump_buffer >> 32);
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_JM_EN),
enable->jm_bm);
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_SHADER_EN),
enable->shader_bm);
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_MMU_L2_EN),
enable->mmu_l2_bm);
/* Due to PRLAM-8186 we need to disable the Tiler before we enable the
* HW counter dump. */
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_TILER_EN),
enable->tiler_bm);
enable->tiler_bm);
kbase_reg_write(kbdev, GPU_CONTROL_REG(PRFCNT_CONFIG),
prfcnt_config | PRFCNT_CONFIG_MODE_MANUAL);
@ -198,6 +204,7 @@ int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx)
*/
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);
@ -205,8 +212,9 @@ int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx)
kbdev->hwcnt.addr >> 32);
/* Start dumping */
KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_SAMPLE, NULL, NULL,
kbdev->hwcnt.addr, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_PRFCNT_SAMPLE, NULL,
kbdev->hwcnt.addr);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_PRFCNT_SAMPLE);
@ -216,6 +224,8 @@ int kbase_instr_hwcnt_request_dump(struct kbase_context *kctx)
unlock:
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
return err;
}
KBASE_EXPORT_SYMBOL(kbase_instr_hwcnt_request_dump);
@ -277,6 +287,7 @@ void kbasep_cache_clean_worker(struct work_struct *data)
spin_unlock_irqrestore(&kbdev->hwcnt.lock, flags);
}
void kbase_instr_hwcnt_sample_done(struct kbase_device *kbdev)
{
unsigned long flags;
@ -348,7 +359,7 @@ int kbase_instr_hwcnt_clear(struct kbase_context *kctx)
goto out;
/* Clear the counters */
KBASE_TRACE_ADD(kbdev, CORE_GPU_PRFCNT_CLEAR, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_PRFCNT_CLEAR, NULL, 0);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_PRFCNT_CLEAR);
@ -369,8 +380,14 @@ int kbase_instr_backend_init(struct kbase_device *kbdev)
init_waitqueue_head(&kbdev->hwcnt.backend.wait);
INIT_WORK(&kbdev->hwcnt.backend.cache_clean_work,
kbasep_cache_clean_worker);
kbdev->hwcnt.backend.triggered = 0;
#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS
kbdev->hwcnt.backend.use_secondary_override = false;
#endif
kbdev->hwcnt.backend.cache_clean_wq =
alloc_workqueue("Mali cache cleaning workqueue", 0, 1);
if (NULL == kbdev->hwcnt.backend.cache_clean_wq)
@ -383,3 +400,12 @@ void kbase_instr_backend_term(struct kbase_device *kbdev)
{
destroy_workqueue(kbdev->hwcnt.backend.cache_clean_wq);
}
#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS
void kbase_instr_backend_debugfs_init(struct kbase_device *kbdev)
{
debugfs_create_bool("hwcnt_use_secondary", S_IRUGO | S_IWUSR,
kbdev->mali_debugfs_directory,
&kbdev->hwcnt.backend.use_secondary_override);
}
#endif

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014, 2016, 2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014, 2016, 2018, 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -47,6 +47,9 @@ enum kbase_instr_state {
struct kbase_instr_backend {
wait_queue_head_t wait;
int triggered;
#ifdef CONFIG_MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS
bool use_secondary_override;
#endif
enum kbase_instr_state state;
struct workqueue_struct *cache_clean_wq;

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2016,2018-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016,2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -79,8 +79,6 @@ static irqreturn_t kbase_job_irq_handler(int irq, void *data)
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;
@ -153,8 +151,6 @@ static irqreturn_t kbase_gpu_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
KBASE_EXPORT_TEST_API(kbase_gpu_irq_handler);
static irq_handler_t kbase_handler_table[] = {
[JOB_IRQ_TAG] = kbase_job_irq_handler,
[MMU_IRQ_TAG] = kbase_mmu_irq_handler,
@ -166,6 +162,35 @@ static irq_handler_t kbase_handler_table[] = {
#define MMU_IRQ_HANDLER MMU_IRQ_TAG
#define GPU_IRQ_HANDLER GPU_IRQ_TAG
/**
* kbase_gpu_irq_test_handler - Variant (for test) of kbase_gpu_irq_handler()
* @irq: IRQ number
* @data: Data associated with this IRQ (i.e. kbdev)
* @val: Value of the GPU_CONTROL_REG(GPU_IRQ_STATUS)
*
* Handle the GPU device interrupt source requests reflected in the
* given source bit-pattern. The test code caller is responsible for
* undertaking the required device power maintenace.
*
* Return: IRQ_HANDLED if the requests are from the GPU device,
* IRQ_NONE otherwise
*/
irqreturn_t kbase_gpu_irq_test_handler(int irq, void *data, u32 val)
{
struct kbase_device *kbdev = kbase_untag(data);
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;
}
KBASE_EXPORT_TEST_API(kbase_gpu_irq_test_handler);
/**
* kbase_set_custom_irq_handler - Set a custom IRQ handler
* @kbdev: Device for which the handler is to be registered

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -148,8 +148,7 @@ int kbase_backend_find_and_release_free_address_space(
*/
if (as_kctx && !kbase_ctx_flag(as_kctx, KCTX_PRIVILEGED) &&
atomic_read(&as_kctx->refcount) == 1) {
if (!kbasep_js_runpool_retain_ctx_nolock(kbdev,
as_kctx)) {
if (!kbase_ctx_sched_inc_refcount_nolock(as_kctx)) {
WARN(1, "Failed to retain active context\n");
spin_unlock_irqrestore(&kbdev->hwaccess_lock,
@ -236,7 +235,7 @@ bool kbase_backend_use_ctx(struct kbase_device *kbdev,
if (kbase_ctx_flag(kctx, KCTX_PRIVILEGED)) {
/* We need to retain it to keep the corresponding address space
*/
kbasep_js_runpool_retain_ctx_nolock(kbdev, kctx);
kbase_ctx_sched_retain_ctx_refcount(kctx);
}
return true;

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2016, 2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016, 2018-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -62,9 +62,6 @@ struct slot_rb {
/**
* 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.
@ -83,8 +80,6 @@ struct slot_rb {
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;

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -26,8 +26,9 @@
#include <mali_kbase.h>
#include <mali_kbase_config.h>
#include <mali_midg_regmap.h>
#include <mali_kbase_tracepoints.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <tl/mali_kbase_tracepoints.h>
#include <mali_linux_trace.h>
#include <mali_kbase_hw.h>
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_reset_gpu.h>
@ -37,17 +38,8 @@
#include <backend/gpu/mali_kbase_irq_internal.h>
#include <backend/gpu/mali_kbase_jm_internal.h>
#define beenthere(kctx, f, a...) \
dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a)
static void kbasep_try_reset_gpu_early_locked(struct kbase_device *kbdev);
static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, int js,
struct kbase_context *kctx)
{
return !kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT));
}
static u64 kbase_job_write_affinity(struct kbase_device *kbdev,
base_jd_core_req core_req,
int js)
@ -87,6 +79,17 @@ static u64 kbase_job_write_affinity(struct kbase_device *kbdev,
kbdev->pm.debug_core_mask[js];
}
if (unlikely(!affinity)) {
#ifdef CONFIG_MALI_BIFROST_DEBUG
u64 shaders_ready =
kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_SHADER);
WARN_ON(!(shaders_ready & kbdev->pm.backend.shaders_avail));
#endif
affinity = kbdev->pm.backend.shaders_avail;
}
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_AFFINITY_NEXT_LO),
affinity & 0xFFFFFFFF);
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_AFFINITY_NEXT_HI),
@ -95,13 +98,90 @@ static u64 kbase_job_write_affinity(struct kbase_device *kbdev,
return affinity;
}
/**
* select_job_chain() - Select which job chain to submit to the GPU
* @katom: Pointer to the atom about to be submitted to the GPU
*
* Selects one of the fragment job chains attached to the special atom at the
* end of a renderpass, or returns the address of the single job chain attached
* to any other type of atom.
*
* Which job chain is selected depends upon whether the tiling phase of the
* renderpass completed normally or was soft-stopped because it used too
* much memory. It also depends upon whether one of the fragment job chains
* has already been run as part of the same renderpass.
*
* Return: GPU virtual address of the selected job chain
*/
static u64 select_job_chain(struct kbase_jd_atom *katom)
{
struct kbase_context *const kctx = katom->kctx;
u64 jc = katom->jc;
struct kbase_jd_renderpass *rp;
lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
if (!(katom->core_req & BASE_JD_REQ_END_RENDERPASS))
return jc;
compiletime_assert((1ull << (sizeof(katom->renderpass_id) * 8)) <=
ARRAY_SIZE(kctx->jctx.renderpasses),
"Should check invalid access to renderpasses");
rp = &kctx->jctx.renderpasses[katom->renderpass_id];
/* We can read a subset of renderpass state without holding
* higher-level locks (but not end_katom, for example).
* If the end-of-renderpass atom is running with as-yet indeterminate
* OOM state then assume that the start atom was not soft-stopped.
*/
switch (rp->state) {
case KBASE_JD_RP_OOM:
/* Tiling ran out of memory.
* Start of incremental rendering, used once.
*/
jc = katom->jc_fragment.norm_read_forced_write;
break;
case KBASE_JD_RP_START:
case KBASE_JD_RP_PEND_OOM:
/* Tiling completed successfully first time.
* Single-iteration rendering, used once.
*/
jc = katom->jc_fragment.norm_read_norm_write;
break;
case KBASE_JD_RP_RETRY_OOM:
/* Tiling ran out of memory again.
* Continuation of incremental rendering, used as
* many times as required.
*/
jc = katom->jc_fragment.forced_read_forced_write;
break;
case KBASE_JD_RP_RETRY:
case KBASE_JD_RP_RETRY_PEND_OOM:
/* Tiling completed successfully this time.
* End of incremental rendering, used once.
*/
jc = katom->jc_fragment.forced_read_norm_write;
break;
default:
WARN_ON(1);
break;
}
dev_dbg(kctx->kbdev->dev,
"Selected job chain 0x%llx for end atom %p in state %d\n",
jc, (void *)katom, (int)rp->state);
katom->jc = jc;
return jc;
}
void kbase_job_hw_submit(struct kbase_device *kbdev,
struct kbase_jd_atom *katom,
int js)
{
struct kbase_context *kctx;
u32 cfg;
u64 jc_head = katom->jc;
u64 const jc_head = select_job_chain(katom);
u64 affinity;
KBASE_DEBUG_ASSERT(kbdev);
@ -112,6 +192,9 @@ void kbase_job_hw_submit(struct kbase_device *kbdev,
/* Command register must be available */
KBASE_DEBUG_ASSERT(kbasep_jm_is_js_free(kbdev, js, kctx));
dev_dbg(kctx->kbdev->dev, "Write JS_HEAD_NEXT 0x%llx for atom %p\n",
jc_head, (void *)katom);
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_LO),
jc_head & 0xFFFFFFFF);
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_HEAD_NEXT_HI),
@ -142,8 +225,8 @@ void kbase_job_hw_submit(struct kbase_device *kbdev,
cfg |= JS_CONFIG_THREAD_PRI(8);
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE) &&
(katom->atom_flags & KBASE_KATOM_FLAG_PROTECTED))
if ((katom->atom_flags & KBASE_KATOM_FLAG_PROTECTED) ||
(katom->core_req & BASE_JD_REQ_END_RENDERPASS))
cfg |= JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK;
if (kbase_hw_has_feature(kbdev,
@ -175,7 +258,7 @@ void kbase_job_hw_submit(struct kbase_device *kbdev,
dev_dbg(kbdev->dev, "JS: Submitting atom %p from ctx %p to js[%d] with head=0x%llx",
katom, kctx, js, jc_head);
KBASE_TRACE_ADD_SLOT_INFO(kbdev, JM_SUBMIT, kctx, katom, jc_head, js,
KBASE_KTRACE_ADD_JM_SLOT_INFO(kbdev, JM_SUBMIT, kctx, katom, jc_head, js,
(u32)affinity);
KBASE_TLSTREAM_AUX_EVENT_JOB_SLOT(kbdev, kctx,
@ -207,6 +290,10 @@ void kbase_job_hw_submit(struct kbase_device *kbdev,
kbdev->hwaccess.backend.slot_rb[js].last_context = katom->kctx;
}
#endif
trace_sysgraph_gpu(SGR_SUBMIT, kctx->id,
kbase_jd_atom_id(kctx, katom), js);
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT),
JS_COMMAND_START);
}
@ -274,7 +361,7 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done)
KBASE_DEBUG_ASSERT(kbdev);
KBASE_TRACE_ADD(kbdev, JM_IRQ, NULL, NULL, 0, done);
KBASE_KTRACE_ADD_JM(kbdev, JM_IRQ, NULL, NULL, 0, done);
end_timestamp = ktime_get();
@ -459,7 +546,7 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done)
*/
kbasep_try_reset_gpu_early_locked(kbdev);
}
KBASE_TRACE_ADD(kbdev, JM_IRQ_END, NULL, NULL, 0, count);
KBASE_KTRACE_ADD_JM(kbdev, JM_IRQ_END, NULL, NULL, 0, count);
}
void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
@ -468,7 +555,7 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
base_jd_core_req core_reqs,
struct kbase_jd_atom *target_katom)
{
#if KBASE_TRACE_ENABLE
#if KBASE_KTRACE_ENABLE
u32 status_reg_before;
u64 job_in_head_before;
u32 status_reg_after;
@ -496,7 +583,7 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
/* We are about to issue a soft stop, so mark the atom as having
* been soft stopped */
target_katom->atom_flags |= KBASE_KATOM_FLAG_BEEN_SOFT_STOPPPED;
target_katom->atom_flags |= KBASE_KATOM_FLAG_BEEN_SOFT_STOPPED;
/* Mark the point where we issue the soft-stop command */
KBASE_TLSTREAM_TL_EVENT_ATOM_SOFTSTOP_ISSUE(kbdev, target_katom);
@ -524,7 +611,7 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
kbase_reg_write(kbdev, JOB_SLOT_REG(js, JS_COMMAND), action);
#if KBASE_TRACE_ENABLE
#if KBASE_KTRACE_ENABLE
status_reg_after = kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_STATUS));
if (status_reg_after == BASE_JD_EVENT_ACTIVE) {
struct kbase_jd_atom *head;
@ -534,36 +621,28 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
head_kctx = head->kctx;
if (status_reg_before == BASE_JD_EVENT_ACTIVE)
KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, head_kctx,
head, job_in_head_before, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_CHECK_HEAD, head_kctx, head, job_in_head_before, js);
else
KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, 0, js);
switch (action) {
case JS_COMMAND_SOFT_STOP:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP, head_kctx, head, head->jc, js);
break;
case JS_COMMAND_SOFT_STOP_0:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_0, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP_0, head_kctx, head, head->jc, js);
break;
case JS_COMMAND_SOFT_STOP_1:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_1, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP_1, head_kctx, head, head->jc, js);
break;
case JS_COMMAND_HARD_STOP:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP, head_kctx, head, head->jc, js);
break;
case JS_COMMAND_HARD_STOP_0:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_0, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_0, head_kctx, head, head->jc, js);
break;
case JS_COMMAND_HARD_STOP_1:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_1, head_kctx,
head, head->jc, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_1, head_kctx, head, head->jc, js);
break;
default:
BUG();
@ -571,36 +650,28 @@ void kbasep_job_slot_soft_or_hard_stop_do_action(struct kbase_device *kbdev,
}
} else {
if (status_reg_before == BASE_JD_EVENT_ACTIVE)
KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL,
job_in_head_before, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, job_in_head_before, js);
else
KBASE_TRACE_ADD_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_CHECK_HEAD, NULL, NULL, 0, js);
switch (action) {
case JS_COMMAND_SOFT_STOP:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP, NULL, NULL, 0,
js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP, NULL, NULL, 0, js);
break;
case JS_COMMAND_SOFT_STOP_0:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_0, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP_0, NULL, NULL, 0, js);
break;
case JS_COMMAND_SOFT_STOP_1:
KBASE_TRACE_ADD_SLOT(kbdev, JM_SOFTSTOP_1, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_SOFTSTOP_1, NULL, NULL, 0, js);
break;
case JS_COMMAND_HARD_STOP:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP, NULL, NULL, 0,
js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP, NULL, NULL, 0, js);
break;
case JS_COMMAND_HARD_STOP_0:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_0, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_0, NULL, NULL, 0, js);
break;
case JS_COMMAND_HARD_STOP_1:
KBASE_TRACE_ADD_SLOT(kbdev, JM_HARDSTOP_1, NULL, NULL,
0, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_HARDSTOP_1, NULL, NULL, 0, js);
break;
default:
BUG();
@ -660,6 +731,70 @@ void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx,
}
}
static int softstop_start_rp_nolock(
struct kbase_context *kctx, struct kbase_va_region *reg)
{
struct kbase_device *const kbdev = kctx->kbdev;
struct kbase_jd_atom *katom;
struct kbase_jd_renderpass *rp;
lockdep_assert_held(&kbdev->hwaccess_lock);
katom = kbase_gpu_inspect(kbdev, 1, 0);
if (!katom) {
dev_dbg(kctx->kbdev->dev, "No atom on job slot\n");
return -ESRCH;
}
if (!(katom->core_req & BASE_JD_REQ_START_RENDERPASS)) {
dev_dbg(kctx->kbdev->dev,
"Atom %p on job slot is not start RP\n", (void *)katom);
return -EPERM;
}
compiletime_assert((1ull << (sizeof(katom->renderpass_id) * 8)) <=
ARRAY_SIZE(kctx->jctx.renderpasses),
"Should check invalid access to renderpasses");
rp = &kctx->jctx.renderpasses[katom->renderpass_id];
if (WARN_ON(rp->state != KBASE_JD_RP_START &&
rp->state != KBASE_JD_RP_RETRY))
return -EINVAL;
dev_dbg(kctx->kbdev->dev, "OOM in state %d with region %p\n",
(int)rp->state, (void *)reg);
if (WARN_ON(katom != rp->start_katom))
return -EINVAL;
dev_dbg(kctx->kbdev->dev, "Adding region %p to list %p\n",
(void *)reg, (void *)&rp->oom_reg_list);
list_move_tail(&reg->link, &rp->oom_reg_list);
dev_dbg(kctx->kbdev->dev, "Added region to list\n");
rp->state = (rp->state == KBASE_JD_RP_START ?
KBASE_JD_RP_PEND_OOM : KBASE_JD_RP_RETRY_PEND_OOM);
kbase_job_slot_softstop(kbdev, 1, katom);
return 0;
}
int kbase_job_slot_softstop_start_rp(struct kbase_context *const kctx,
struct kbase_va_region *const reg)
{
struct kbase_device *const kbdev = kctx->kbdev;
int err;
unsigned long flags;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
err = softstop_start_rp_nolock(kctx, reg);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
return err;
}
void kbase_jm_wait_for_zero_jobs(struct kbase_context *kctx)
{
struct kbase_device *kbdev = kctx->kbdev;
@ -749,6 +884,9 @@ KBASE_EXPORT_TEST_API(kbase_job_slot_term);
void kbase_job_slot_softstop_swflags(struct kbase_device *kbdev, int js,
struct kbase_jd_atom *target_katom, u32 sw_flags)
{
dev_dbg(kbdev->dev, "Soft-stop atom %p with flags 0x%x (s:%d)\n",
target_katom, sw_flags, js);
KBASE_DEBUG_ASSERT(!(sw_flags & JS_COMMAND_MASK));
kbase_backend_soft_hard_stop_slot(kbdev, NULL, js, target_katom,
JS_COMMAND_SOFT_STOP | sw_flags);
@ -907,7 +1045,7 @@ static void kbasep_reset_timeout_worker(struct work_struct *data)
KBASE_RESET_GPU_SILENT)
silent = true;
KBASE_TRACE_ADD(kbdev, JM_BEGIN_RESET_WORKER, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD_JM(kbdev, JM_BEGIN_RESET_WORKER, NULL, NULL, 0u, 0);
/* Disable GPU hardware counters.
* This call will block until counters are disabled.
@ -1035,7 +1173,7 @@ static void kbasep_reset_timeout_worker(struct work_struct *data)
dev_err(kbdev->dev, "Reset complete");
/* Try submitting some jobs to restart processing */
KBASE_TRACE_ADD(kbdev, JM_SUBMIT_AFTER_RESET, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD_JM(kbdev, JM_SUBMIT_AFTER_RESET, NULL, NULL, 0u, 0);
kbase_js_sched_all(kbdev);
/* Process any pending slot updates */
@ -1050,7 +1188,7 @@ static void kbasep_reset_timeout_worker(struct work_struct *data)
kbase_hwcnt_context_enable(kbdev->hwcnt_gpu_ctx);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
KBASE_TRACE_ADD(kbdev, JM_END_RESET_WORKER, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD_JM(kbdev, JM_END_RESET_WORKER, NULL, NULL, 0u, 0);
}
static enum hrtimer_restart kbasep_reset_timer_callback(struct hrtimer *timer)
@ -1281,4 +1419,3 @@ void kbase_reset_gpu_term(struct kbase_device *kbdev)
{
destroy_workqueue(kbdev->hwaccess.backend.reset_workq);
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2016, 2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -34,6 +34,7 @@
#include <linux/atomic.h>
#include <backend/gpu/mali_kbase_jm_rb.h>
#include <backend/gpu/mali_kbase_device_internal.h>
/**
* kbase_job_submit_nolock() - Submit a job to a certain job-slot
@ -70,6 +71,13 @@ static inline char *kbasep_make_job_slot_string(int js, char *js_string,
}
#endif
static inline int kbasep_jm_is_js_free(struct kbase_device *kbdev, int js,
struct kbase_context *kctx)
{
return !kbase_reg_read(kbdev, JOB_SLOT_REG(js, JS_COMMAND_NEXT));
}
/**
* kbase_job_hw_submit() - Submit a job to the GPU
* @kbdev: Device pointer

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -26,12 +26,12 @@
*/
#include <mali_kbase.h>
#include <gpu/mali_kbase_gpu_fault.h>
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_jm.h>
#include <mali_kbase_js.h>
#include <mali_kbase_tracepoints.h>
#include <tl/mali_kbase_tracepoints.h>
#include <mali_kbase_hwcnt_context.h>
#include <mali_kbase_10969_workaround.h>
#include <mali_kbase_reset_gpu.h>
#include <backend/gpu/mali_kbase_cache_policy_backend.h>
#include <backend/gpu/mali_kbase_device_internal.h>
@ -299,9 +299,6 @@ static void kbase_gpu_release_atom(struct kbase_device *kbdev,
case KBASE_ATOM_GPU_RB_READY:
/* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */
case KBASE_ATOM_GPU_RB_WAITING_AFFINITY:
/* ***FALLTHROUGH: TRANSITION TO LOWER STATE*** */
case KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE:
break;
@ -617,11 +614,15 @@ static int kbase_jm_enter_protected_mode(struct kbase_device *kbdev,
return -EAGAIN;
}
if (kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_L2) ||
kbase_pm_get_trans_cores(kbdev, KBASE_PM_CORE_L2)) {
if (kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_L2) ||
kbase_pm_get_trans_cores(kbdev,
KBASE_PM_CORE_L2) ||
kbase_is_gpu_lost(kbdev)) {
/*
* The L2 is still powered, wait for all the users to
* finish with it before doing the actual reset.
* The L2 is still powered, wait for all
* the users to finish with it before doing
* the actual reset.
*/
return -EAGAIN;
}
@ -809,7 +810,11 @@ void kbase_backend_slot_update(struct kbase_device *kbdev)
lockdep_assert_held(&kbdev->hwaccess_lock);
#ifdef CONFIG_MALI_ARBITER_SUPPORT
if (kbase_reset_gpu_is_active(kbdev) || kbase_is_gpu_lost(kbdev))
#else
if (kbase_reset_gpu_is_active(kbdev))
#endif
return;
for (js = 0; js < kbdev->gpu_props.num_job_slots; js++) {
@ -834,8 +839,7 @@ void kbase_backend_slot_update(struct kbase_device *kbdev)
break;
case KBASE_ATOM_GPU_RB_WAITING_BLOCKED:
if (katom[idx]->atom_flags &
KBASE_KATOM_FLAG_X_DEP_BLOCKED)
if (kbase_js_atom_blocked_on_x_dep(katom[idx]))
break;
katom[idx]->gpu_rb_state =
@ -930,12 +934,6 @@ void kbase_backend_slot_update(struct kbase_device *kbdev)
if (!cores_ready)
break;
katom[idx]->gpu_rb_state =
KBASE_ATOM_GPU_RB_WAITING_AFFINITY;
/* ***TRANSITION TO HIGHER STATE*** */
/* fallthrough */
case KBASE_ATOM_GPU_RB_WAITING_AFFINITY:
katom[idx]->gpu_rb_state =
KBASE_ATOM_GPU_RB_READY;
@ -967,11 +965,11 @@ void kbase_backend_slot_update(struct kbase_device *kbdev)
other_slots_busy(kbdev, js))
break;
if ((kbdev->serialize_jobs &
KBASE_SERIALIZE_RESET) &&
kbase_reset_gpu_is_active(kbdev))
#ifdef CONFIG_MALI_GEM5_BUILD
if (!kbasep_jm_is_js_free(kbdev, js,
katom[idx]->kctx))
break;
#endif
/* Check if this job needs the cycle counter
* enabled before submission */
if (katom[idx]->core_req & BASE_JD_REQ_PERMON)
@ -1015,6 +1013,8 @@ void kbase_backend_run_atom(struct kbase_device *kbdev,
struct kbase_jd_atom *katom)
{
lockdep_assert_held(&kbdev->hwaccess_lock);
dev_dbg(kbdev->dev, "Backend running atom %p\n", (void *)katom);
kbase_gpu_enqueue_atom(kbdev, katom);
kbase_backend_slot_update(kbdev);
}
@ -1073,6 +1073,10 @@ void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js,
struct kbase_jd_atom *katom = kbase_gpu_inspect(kbdev, js, 0);
struct kbase_context *kctx = katom->kctx;
dev_dbg(kbdev->dev,
"Atom %p completed on hw with code 0x%x and job_tail 0x%llx (s:%d)\n",
(void *)katom, completion_code, job_tail, js);
lockdep_assert_held(&kbdev->hwaccess_lock);
/*
@ -1125,12 +1129,11 @@ void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js,
if (!kbase_ctx_flag(katom->kctx, KCTX_DYING))
dev_warn(kbdev->dev, "error detected from slot %d, job status 0x%08x (%s)",
js, completion_code,
kbase_exception_name
(kbdev,
kbase_gpu_exception_name(
completion_code));
#if KBASE_TRACE_DUMP_ON_JOB_SLOT_ERROR != 0
KBASE_TRACE_DUMP(kbdev);
#if KBASE_KTRACE_DUMP_ON_JOB_SLOT_ERROR != 0
KBASE_KTRACE_DUMP(kbdev);
#endif
kbasep_js_clear_submit_allowed(js_devdata, katom->kctx);
@ -1184,23 +1187,22 @@ void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js,
}
}
KBASE_TRACE_ADD_SLOT_INFO(kbdev, JM_JOB_DONE, kctx, katom, katom->jc,
js, completion_code);
KBASE_KTRACE_ADD_JM_SLOT_INFO(kbdev, JM_JOB_DONE, kctx, katom, katom->jc, js, completion_code);
if (job_tail != 0 && job_tail != katom->jc) {
bool was_updated = (job_tail != katom->jc);
/* Some of the job has been executed */
dev_dbg(kbdev->dev,
"Update job chain address of atom %p to resume from 0x%llx\n",
(void *)katom, job_tail);
/* Some of the job has been executed, so we update the job chain
* address to where we should resume from */
katom->jc = job_tail;
if (was_updated)
KBASE_TRACE_ADD_SLOT(kbdev, JM_UPDATE_HEAD, katom->kctx,
katom, job_tail, js);
KBASE_KTRACE_ADD_JM_SLOT(kbdev, JM_UPDATE_HEAD, katom->kctx,
katom, job_tail, js);
}
/* Only update the event code for jobs that weren't cancelled */
if (katom->event_code != BASE_JD_EVENT_JOB_CANCELLED)
katom->event_code = (base_jd_event_code)completion_code;
katom->event_code = (enum base_jd_event_code)completion_code;
/* Complete the job, and start new ones
*
@ -1250,8 +1252,9 @@ void kbase_gpu_complete_hw(struct kbase_device *kbdev, int js,
katom = kbase_jm_complete(kbdev, katom, end_timestamp);
if (katom) {
/* Cross-slot dependency has now become runnable. Try to submit
* it. */
dev_dbg(kbdev->dev,
"Cross-slot dependency %p has become runnable.\n",
(void *)katom);
/* Check if there are lower priority jobs to soft stop */
kbase_job_slot_ctx_priority_check_locked(kctx, katom);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -301,8 +301,7 @@ void kbase_backend_ctx_count_changed(struct kbase_device *kbdev)
HR_TIMER_DELAY_NSEC(js_devdata->scheduling_period_ns),
HRTIMER_MODE_REL);
KBASE_TRACE_ADD(kbdev, JS_POLICY_TIMER_START, NULL, NULL, 0u,
0u);
KBASE_KTRACE_ADD_JM(kbdev, JS_POLICY_TIMER_START, NULL, NULL, 0u, 0u);
}
}
@ -313,7 +312,6 @@ int kbase_backend_timer_init(struct kbase_device *kbdev)
hrtimer_init(&backend->scheduling_timer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL);
backend->scheduling_timer.function = timer_callback;
backend->timer_running = false;
return 0;

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -21,7 +21,6 @@
*
*/
#include <mali_kbase.h>
#include <mali_kbase_bits.h>
#include <mali_kbase_config_defaults.h>
@ -76,7 +75,7 @@ static const struct l2_mmu_config_limit limits[] = {
{KBASE_3BIT_AID_32, GENMASK(17, 15), 15} },
};
void kbase_set_mmu_quirks(struct kbase_device *kbdev)
int kbase_set_mmu_quirks(struct kbase_device *kbdev)
{
/* All older GPUs had 2 bits for both fields, this is a default */
struct l2_mmu_config_limit limit = {
@ -101,18 +100,23 @@ void kbase_set_mmu_quirks(struct kbase_device *kbdev)
mmu_config = kbase_reg_read(kbdev, GPU_CONTROL_REG(L2_MMU_CONFIG));
if (kbase_is_gpu_lost(kbdev))
return -EIO;
mmu_config &= ~(limit.read.mask | limit.write.mask);
/* Can't use FIELD_PREP() macro here as the mask isn't constant */
mmu_config |= (limit.read.value << limit.read.shift) |
(limit.write.value << limit.write.shift);
(limit.write.value << limit.write.shift);
kbdev->hw_quirks_mmu = mmu_config;
if (kbdev->system_coherency == COHERENCY_ACE) {
/* Allow memory configuration disparity to be ignored,
* we optimize the use of shared memory and thus we
* expect some disparity in the memory configuration.
*/
* we optimize the use of shared memory and thus we
* expect some disparity in the memory configuration.
*/
kbdev->hw_quirks_mmu |= L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY;
}
return 0;
}

View File

@ -20,13 +20,22 @@
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
*/
#ifndef _KBASE_L2_MMU_CONFIG_H_
@ -38,7 +47,9 @@
*
* Use this function to initialise the hw_quirks_mmu field, for instance to set
* the MAX_READS and MAX_WRITES to sane defaults for each GPU.
*
* Return: Zero for succeess or a Linux error code
*/
void kbase_set_mmu_quirks(struct kbase_device *kbdev);
int kbase_set_mmu_quirks(struct kbase_device *kbdev);
#endif /* _KBASE_L2_MMU_CONFIG_H */

View File

@ -1,62 +0,0 @@
/*
*
* (C) COPYRIGHT 2014-2015, 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* 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 _KBASE_MMU_HW_DIRECT_H_
#define _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: Pointer to the kbase device for which the interrupt happened.
* @irq_stat: Value of the MMU_IRQ_STATUS register.
*/
void kbase_mmu_interrupt(struct kbase_device *kbdev, u32 irq_stat);
/**
* kbase_mmu_bus_fault_interrupt - Process a bus fault interrupt.
*
* Process the bus fault interrupt that was reported for a particular GPU
* address space.
*
* @kbdev: Pointer to the kbase device for which bus fault was reported.
* @status: Value of the GPU_FAULTSTATUS register.
* @as_nr: GPU address space for which the bus fault occurred.
*
* Return: zero if the operation was successful, non-zero otherwise.
*/
int kbase_mmu_bus_fault_interrupt(struct kbase_device *kbdev,
u32 status, u32 as_nr);
#endif /* _KBASE_MMU_HW_DIRECT_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -26,16 +26,18 @@
*/
#include <mali_kbase.h>
#include <mali_midg_regmap.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_pm.h>
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_hwcnt_context.h>
#include <backend/gpu/mali_kbase_js_internal.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <backend/gpu/mali_kbase_jm_internal.h>
#include <mali_kbase_hwcnt_context.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <backend/gpu/mali_kbase_devfreq.h>
#include <mali_kbase_dummy_job_wa.h>
#include <mali_kbase_irq_internal.h>
static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data);
static void kbase_pm_hwcnt_disable_worker(struct work_struct *data);
@ -138,6 +140,9 @@ int kbase_hwaccess_pm_init(struct kbase_device *kbdev)
kbdev->pm.backend.ca_cores_enabled = ~0ull;
kbdev->pm.backend.gpu_powered = false;
kbdev->pm.suspending = false;
#ifdef CONFIG_MALI_ARBITER_SUPPORT
kbdev->pm.gpu_lost = false;
#endif
#ifdef CONFIG_MALI_BIFROST_DEBUG
kbdev->pm.backend.driver_ready_for_irqs = false;
#endif /* CONFIG_MALI_BIFROST_DEBUG */
@ -244,7 +249,6 @@ static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data)
pm.backend.gpu_poweroff_wait_work);
struct kbase_pm_device_data *pm = &kbdev->pm;
struct kbase_pm_backend_data *backend = &pm->backend;
struct kbasep_js_device_data *js_devdata = &kbdev->js_data;
unsigned long flags;
/* Wait for power transitions to complete. We do this with no locks held
@ -252,8 +256,7 @@ static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data)
*/
kbase_pm_wait_for_desired_state(kbdev);
mutex_lock(&js_devdata->runpool_mutex);
mutex_lock(&kbdev->pm.lock);
kbase_pm_lock(kbdev);
if (!backend->poweron_required) {
unsigned long flags;
@ -271,11 +274,9 @@ static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data)
* process. Interrupts are disabled so no more faults
* should be generated at this point.
*/
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
kbase_flush_mmu_wqs(kbdev);
mutex_lock(&js_devdata->runpool_mutex);
mutex_lock(&kbdev->pm.lock);
kbase_pm_lock(kbdev);
/* Turn off clock now that fault have been handled. We
* dropped locks so poweron_required may have changed -
@ -301,8 +302,7 @@ static void kbase_pm_gpu_poweroff_wait_wq(struct work_struct *data)
}
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
wake_up(&kbdev->pm.backend.poweroff_wait);
}
@ -517,14 +517,12 @@ KBASE_EXPORT_TEST_API(kbase_pm_wait_for_poweroff_complete);
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);
kbase_pm_lock(kbdev);
/* A suspend won't happen during startup/insmod */
KBASE_DEBUG_ASSERT(!kbase_pm_is_suspending(kbdev));
@ -533,8 +531,7 @@ int kbase_hwaccess_pm_powerup(struct kbase_device *kbdev,
* them. */
ret = kbase_pm_init_hw(kbdev, flags);
if (ret) {
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
return ret;
}
@ -564,8 +561,7 @@ int kbase_hwaccess_pm_powerup(struct kbase_device *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);
kbase_pm_unlock(kbdev);
return 0;
}
@ -615,7 +611,7 @@ void kbase_pm_power_changed(struct kbase_device *kbdev)
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_pm_update_state(kbdev);
kbase_backend_slot_update(kbdev);
kbase_backend_slot_update(kbdev);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
@ -627,6 +623,11 @@ void kbase_pm_set_debug_core_mask(struct kbase_device *kbdev,
lockdep_assert_held(&kbdev->hwaccess_lock);
lockdep_assert_held(&kbdev->pm.lock);
if (kbase_dummy_job_wa_enabled(kbdev)) {
dev_warn(kbdev->dev, "Change of core mask not supported for slot 0 as dummy job WA is enabled");
new_core_mask_js0 = kbdev->pm.debug_core_mask[0];
}
kbdev->pm.debug_core_mask[0] = new_core_mask_js0;
kbdev->pm.debug_core_mask[1] = new_core_mask_js1;
kbdev->pm.debug_core_mask[2] = new_core_mask_js2;
@ -648,20 +649,16 @@ void kbase_hwaccess_pm_gpu_idle(struct kbase_device *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_lock(kbdev);
kbase_pm_do_poweroff(kbdev);
kbase_backend_timer_suspend(kbdev);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
kbase_pm_wait_for_poweroff_complete(kbdev);
@ -671,16 +668,80 @@ void kbase_hwaccess_pm_suspend(struct kbase_device *kbdev)
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);
kbase_pm_lock(kbdev);
kbdev->pm.suspending = false;
#ifdef CONFIG_MALI_ARBITER_SUPPORT
kbdev->pm.gpu_lost = false;
#endif
kbase_pm_do_poweron(kbdev, true);
kbase_backend_timer_resume(kbdev);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
}
#ifdef CONFIG_MALI_ARBITER_SUPPORT
void kbase_pm_handle_gpu_lost(struct kbase_device *kbdev)
{
unsigned long flags;
struct kbase_pm_backend_data *backend = &kbdev->pm.backend;
ktime_t end_timestamp = ktime_get();
/* Full GPU reset will have been done by hypervisor, so cancel */
atomic_set(&kbdev->hwaccess.backend.reset_gpu,
KBASE_RESET_GPU_NOT_PENDING);
hrtimer_cancel(&kbdev->hwaccess.backend.reset_timer);
/* GPU is no longer mapped to VM. So no interrupts will be received
* and Mali registers have been replaced by dummy RAM
*/
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
spin_lock(&kbdev->mmu_mask_change);
kbdev->irq_reset_flush = true;
spin_unlock(&kbdev->mmu_mask_change);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
kbase_synchronize_irqs(kbdev);
kbase_flush_mmu_wqs(kbdev);
kbdev->irq_reset_flush = false;
/* Clear all jobs running on the GPU */
mutex_lock(&kbdev->pm.lock);
kbdev->pm.gpu_lost = true;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbdev->protected_mode = false;
if (!kbdev->pm.backend.protected_entry_transition_override)
kbase_backend_reset(kbdev, &end_timestamp);
kbase_pm_metrics_update(kbdev, NULL);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
/* Cancel any pending HWC dumps */
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);
/* Wait for all threads keeping GPU active to complete */
mutex_unlock(&kbdev->pm.lock);
wait_event(kbdev->pm.zero_active_count_wait,
kbdev->pm.active_count == 0);
mutex_lock(&kbdev->pm.lock);
/* Update state to GPU off */
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbdev->pm.backend.shaders_desired = false;
kbdev->pm.backend.l2_desired = false;
backend->l2_state = KBASE_L2_OFF;
backend->shaders_state = KBASE_SHADERS_OFF_CORESTACK_OFF;
kbdev->pm.backend.gpu_powered = false;
backend->poweroff_wait_in_progress = false;
KBASE_KTRACE_ADD(kbdev, PM_WAKE_WAITERS, NULL, 0);
wake_up(&kbdev->pm.backend.gpu_in_desired_state_wait);
kbase_gpu_cache_clean_wait_complete(kbdev);
backend->poweroff_wait_in_progress = false;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
wake_up(&kbdev->pm.backend.poweroff_wait);
mutex_unlock(&kbdev->pm.lock);
}
#endif /* CONFIG_MALI_ARBITER_SUPPORT */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2013-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2013-2018, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -30,6 +30,7 @@
#ifdef MALI_BIFROST_NO_MALI
#include <backend/gpu/mali_kbase_model_dummy.h>
#endif
#include <mali_kbase_dummy_job_wa.h>
int kbase_pm_ca_init(struct kbase_device *kbdev)
{
@ -64,6 +65,11 @@ void kbase_devfreq_set_core_mask(struct kbase_device *kbdev, u64 core_mask)
goto unlock;
}
if (kbase_dummy_job_wa_enabled(kbdev)) {
dev_err(kbdev->dev, "Dynamic core scaling not supported as dummy job WA is enabled");
goto unlock;
}
pm_backend->ca_cores_enabled = core_mask;
kbase_pm_update_state(kbdev);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -301,9 +301,17 @@ union kbase_pm_policy_data {
* @l2_always_on: If true, disable powering down of l2 cache.
* @shaders_state: The current state of the shader state machine.
* @shaders_avail: This is updated by the state machine when it is in a state
* where it can handle changes to the core availability. This
* is internal to the shader state machine and should *not* be
* modified elsewhere.
* where it can write to the SHADER_PWRON or PWROFF registers
* to have the same set of available cores as specified by
* @shaders_desired_mask. So it would eventually have the same
* value as @shaders_desired_mask and would precisely indicate
* the cores that are currently available. This is internal to
* shader state machine and should *not* be modified elsewhere.
* @shaders_desired_mask: This is updated by the state machine when it is in
* a state where it can handle changes to the core
* availability (either by DVFS or sysfs). This is
* internal to the shader state machine and should
* *not* be modified elsewhere.
* @shaders_desired: True if the PM active count or power policy requires the
* shader cores to be on. This is used as an input to the
* shader power state machine. The current state of the
@ -401,6 +409,7 @@ struct kbase_pm_backend_data {
enum kbase_l2_core_state l2_state;
enum kbase_shader_core_state shaders_state;
u64 shaders_avail;
u64 shaders_desired_mask;
bool l2_desired;
bool l2_always_on;
bool shaders_desired;

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,16 +21,14 @@
*
*/
/*
* Base kernel Power Management hardware control
*/
#include <mali_kbase.h>
#include <mali_kbase_config_defaults.h>
#include <mali_midg_regmap.h>
#include <mali_kbase_tracepoints.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <tl/mali_kbase_tracepoints.h>
#include <mali_kbase_pm.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_smc.h>
@ -42,6 +41,10 @@
#include <backend/gpu/mali_kbase_irq_internal.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <backend/gpu/mali_kbase_l2_mmu_config.h>
#include <mali_kbase_dummy_job_wa.h>
#ifdef CONFIG_MALI_ARBITER_SUPPORT
#include <arbiter/mali_kbase_arbiter_pm.h>
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
#include <linux/of.h>
@ -280,16 +283,13 @@ static void kbase_pm_invoke(struct kbase_device *kbdev,
if (action == ACTION_PWRON)
switch (core_type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_PWRON, NULL, NULL, 0u,
lo);
KBASE_KTRACE_ADD(kbdev, PM_PWRON, NULL, cores);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_PWRON_TILER, NULL,
NULL, 0u, lo);
KBASE_KTRACE_ADD(kbdev, PM_PWRON_TILER, NULL, cores);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_PWRON_L2, NULL, NULL,
0u, lo);
KBASE_KTRACE_ADD(kbdev, PM_PWRON_L2, NULL, cores);
break;
default:
break;
@ -297,16 +297,13 @@ static void kbase_pm_invoke(struct kbase_device *kbdev,
else if (action == ACTION_PWROFF)
switch (core_type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_PWROFF, NULL, NULL,
0u, lo);
KBASE_KTRACE_ADD(kbdev, PM_PWROFF, NULL, cores);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_PWROFF_TILER, NULL,
NULL, 0u, lo);
KBASE_KTRACE_ADD(kbdev, PM_PWROFF_TILER, NULL, cores);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_PWROFF_L2, NULL, NULL,
0u, lo);
KBASE_KTRACE_ADD(kbdev, PM_PWROFF_L2, NULL, cores);
/* disable snoops before L2 is turned off */
kbase_pm_cache_snoop_disable(kbdev);
break;
@ -315,11 +312,18 @@ static void kbase_pm_invoke(struct kbase_device *kbdev,
}
}
if (lo != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg), lo);
if (hi != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg + 4), hi);
if (kbase_dummy_job_wa_enabled(kbdev) &&
action == ACTION_PWRON &&
core_type == KBASE_PM_CORE_SHADER &&
!(kbdev->dummy_job_wa.flags &
KBASE_DUMMY_JOB_WA_FLAG_LOGICAL_SHADER_POWER)) {
kbase_dummy_job_wa_execute(kbdev, cores);
} else {
if (lo != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg), lo);
if (hi != 0)
kbase_reg_write(kbdev, GPU_CONTROL_REG(reg + 4), hi);
}
}
/**
@ -436,16 +440,13 @@ u64 kbase_pm_get_ready_cores(struct kbase_device *kbdev,
switch (type) {
case KBASE_PM_CORE_SHADER:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED, NULL, NULL, 0u,
(u32) result);
KBASE_KTRACE_ADD(kbdev, PM_CORES_POWERED, NULL, result);
break;
case KBASE_PM_CORE_TILER:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_TILER, NULL, NULL, 0u,
(u32) result);
KBASE_KTRACE_ADD(kbdev, PM_CORES_POWERED_TILER, NULL, result);
break;
case KBASE_PM_CORE_L2:
KBASE_TRACE_ADD(kbdev, PM_CORES_POWERED_L2, NULL, NULL, 0u,
(u32) result);
KBASE_KTRACE_ADD(kbdev, PM_CORES_POWERED_L2, NULL, result);
break;
default:
break;
@ -535,7 +536,7 @@ static const char *kbase_l2_core_state_to_string(enum kbase_l2_core_state state)
return strings[state];
}
static u64 kbase_pm_l2_update_state(struct kbase_device *kbdev)
static int kbase_pm_l2_update_state(struct kbase_device *kbdev)
{
struct kbase_pm_backend_data *backend = &kbdev->pm.backend;
u64 l2_present = kbdev->gpu_props.props.raw_props.l2_present;
@ -555,6 +556,13 @@ static u64 kbase_pm_l2_update_state(struct kbase_device *kbdev)
u64 tiler_ready = kbase_pm_get_ready_cores(kbdev,
KBASE_PM_CORE_TILER);
/*
* kbase_pm_get_ready_cores and kbase_pm_get_trans_cores
* are vulnerable to corruption if gpu is lost
*/
if (kbase_is_gpu_lost(kbdev))
return -EIO;
/* mask off ready from trans in case transitions finished
* between the register reads
*/
@ -592,10 +600,7 @@ static u64 kbase_pm_l2_update_state(struct kbase_device *kbdev)
case KBASE_L2_PEND_ON:
if (!l2_trans && l2_ready == l2_present && !tiler_trans
&& tiler_ready == tiler_present) {
KBASE_TRACE_ADD(kbdev,
PM_CORES_CHANGE_AVAILABLE_TILER,
NULL, NULL, 0u,
(u32)tiler_ready);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER, NULL, tiler_ready);
/*
* Ensure snoops are enabled after L2 is powered
* up. Note that kbase keeps track of the snoop
@ -765,8 +770,7 @@ static u64 kbase_pm_l2_update_state(struct kbase_device *kbdev)
kbase_gpu_start_cache_clean_nolock(
kbdev);
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER,
NULL, NULL, 0u, 0u);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE_TILER, NULL, 0u);
backend->l2_state = KBASE_L2_PEND_OFF;
break;
@ -811,8 +815,6 @@ static u64 kbase_pm_l2_update_state(struct kbase_device *kbdev)
&kbdev->pm.backend.gpu_poweroff_wait_work);
}
if (backend->l2_state == KBASE_L2_ON)
return l2_present;
return 0;
}
@ -889,13 +891,14 @@ static const char *kbase_shader_core_state_to_string(
return strings[state];
}
static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
static int kbase_pm_shaders_update_state(struct kbase_device *kbdev)
{
struct kbase_pm_backend_data *backend = &kbdev->pm.backend;
struct kbasep_pm_tick_timer_state *stt =
&kbdev->pm.backend.shader_tick_timer;
enum kbase_shader_core_state prev_state;
u64 stacks_avail = 0;
int err = 0;
lockdep_assert_held(&kbdev->hwaccess_lock);
@ -917,6 +920,15 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
stacks_ready = kbase_pm_get_ready_cores(kbdev, KBASE_PM_CORE_STACK);
}
/*
* kbase_pm_get_ready_cores and kbase_pm_get_trans_cores
* are vulnerable to corruption if gpu is lost
*/
if (kbase_is_gpu_lost(kbdev)) {
err = -EIO;
break;
}
/* mask off ready from trans in case transitions finished
* between the register reads
*/
@ -931,7 +943,8 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
* except at certain points where we can handle it,
* i.e. off and SHADERS_ON_CORESTACK_ON.
*/
backend->shaders_avail = kbase_pm_ca_get_core_mask(kbdev);
backend->shaders_desired_mask =
kbase_pm_ca_get_core_mask(kbdev);
backend->pm_shaders_core_mask = 0;
if (backend->shaders_desired &&
@ -958,6 +971,8 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
case KBASE_SHADERS_OFF_CORESTACK_PEND_ON:
if (!stacks_trans && stacks_ready == stacks_avail) {
backend->shaders_avail =
backend->shaders_desired_mask;
kbase_pm_invoke(kbdev, KBASE_PM_CORE_SHADER,
backend->shaders_avail, ACTION_PWRON);
@ -967,9 +982,7 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
case KBASE_SHADERS_PEND_ON_CORESTACK_ON:
if (!shaders_trans && shaders_ready == backend->shaders_avail) {
KBASE_TRACE_ADD(kbdev,
PM_CORES_CHANGE_AVAILABLE,
NULL, NULL, 0u, (u32)shaders_ready);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, shaders_ready);
backend->pm_shaders_core_mask = shaders_ready;
backend->hwcnt_desired = true;
if (backend->hwcnt_disabled) {
@ -983,11 +996,12 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
break;
case KBASE_SHADERS_ON_CORESTACK_ON:
backend->shaders_avail = kbase_pm_ca_get_core_mask(kbdev);
backend->shaders_desired_mask =
kbase_pm_ca_get_core_mask(kbdev);
/* If shaders to change state, trigger a counter dump */
if (!backend->shaders_desired ||
(backend->shaders_avail != shaders_ready)) {
(backend->shaders_desired_mask != shaders_ready)) {
backend->hwcnt_desired = false;
if (!backend->hwcnt_disabled)
kbase_pm_trigger_hwcnt_disable(kbdev);
@ -997,7 +1011,7 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
break;
case KBASE_SHADERS_ON_CORESTACK_ON_RECHECK:
backend->shaders_avail =
backend->shaders_desired_mask =
kbase_pm_ca_get_core_mask(kbdev);
if (!backend->hwcnt_disabled) {
@ -1005,6 +1019,10 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
;
} else if (!backend->shaders_desired) {
if (kbdev->pm.backend.protected_transition_override ||
#ifdef CONFIG_MALI_ARBITER_SUPPORT
kbase_pm_is_suspending(kbdev) ||
kbase_pm_is_gpu_lost(kbdev) ||
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
!stt->configured_ticks ||
WARN_ON(stt->cancel_queued)) {
backend->shaders_state = KBASE_SHADERS_WAIT_FINISHED_CORESTACK_ON;
@ -1031,19 +1049,20 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
backend->shaders_state = KBASE_SHADERS_WAIT_OFF_CORESTACK_ON;
}
} else if (backend->shaders_avail & ~shaders_ready) {
} else if (backend->shaders_desired_mask & ~shaders_ready) {
/* set cores ready but not available to
* meet KBASE_SHADERS_PEND_ON_CORESTACK_ON
* check pass
*/
backend->shaders_avail |= shaders_ready;
backend->shaders_avail =
(backend->shaders_desired_mask | shaders_ready);
kbase_pm_invoke(kbdev, KBASE_PM_CORE_SHADER,
backend->shaders_avail & ~shaders_ready,
ACTION_PWRON);
backend->shaders_state =
KBASE_SHADERS_PEND_ON_CORESTACK_ON;
} else if (shaders_ready & ~backend->shaders_avail) {
} else if (shaders_ready & ~backend->shaders_desired_mask) {
backend->shaders_state =
KBASE_SHADERS_WAIT_GPU_IDLE;
} else {
@ -1063,6 +1082,11 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
backend->shaders_state = KBASE_SHADERS_ON_CORESTACK_ON_RECHECK;
} else if (stt->remaining_ticks == 0) {
backend->shaders_state = KBASE_SHADERS_WAIT_FINISHED_CORESTACK_ON;
#ifdef CONFIG_MALI_ARBITER_SUPPORT
} else if (kbase_pm_is_suspending(kbdev) ||
kbase_pm_is_gpu_lost(kbdev)) {
backend->shaders_state = KBASE_SHADERS_WAIT_FINISHED_CORESTACK_ON;
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
}
break;
@ -1104,21 +1128,24 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
* meet KBASE_SHADERS_PEND_ON_CORESTACK_ON
* check pass
*/
backend->shaders_avail &= shaders_ready;
/* shaders_desired_mask shall be a subset of
* shaders_ready
*/
WARN_ON(backend->shaders_desired_mask & ~shaders_ready);
WARN_ON(!(backend->shaders_desired_mask & shaders_ready));
backend->shaders_avail =
backend->shaders_desired_mask;
kbase_pm_invoke(kbdev, KBASE_PM_CORE_SHADER,
shaders_ready & ~backend->shaders_avail, ACTION_PWROFF);
backend->shaders_state = KBASE_SHADERS_PEND_ON_CORESTACK_ON;
KBASE_TRACE_ADD(kbdev,
PM_CORES_CHANGE_AVAILABLE,
NULL, NULL, 0u,
(u32)(shaders_ready & ~backend->shaders_avail));
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, (shaders_ready & ~backend->shaders_avail));
} else {
kbase_pm_invoke(kbdev, KBASE_PM_CORE_SHADER,
shaders_ready, ACTION_PWROFF);
KBASE_TRACE_ADD(kbdev,
PM_CORES_CHANGE_AVAILABLE,
NULL, NULL, 0u, 0u);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, 0u);
backend->shaders_state = KBASE_SHADERS_PEND_OFF_CORESTACK_ON;
}
@ -1167,6 +1194,8 @@ static void kbase_pm_shaders_update_state(struct kbase_device *kbdev)
backend->shaders_state));
} while (backend->shaders_state != prev_state);
return err;
}
static bool kbase_pm_is_in_desired_state_nolock(struct kbase_device *kbdev)
@ -1259,24 +1288,29 @@ void kbase_pm_update_state(struct kbase_device *kbdev)
if (!kbdev->pm.backend.gpu_powered)
return; /* Do nothing if the GPU is off */
kbase_pm_l2_update_state(kbdev);
kbase_pm_shaders_update_state(kbdev);
if (kbase_pm_l2_update_state(kbdev))
return;
if (kbase_pm_shaders_update_state(kbdev))
return;
/* If the shaders just turned off, re-invoke the L2 state machine, in
* case it was waiting for the shaders to turn off before powering down
* the L2.
*/
if (prev_shaders_state != KBASE_SHADERS_OFF_CORESTACK_OFF &&
kbdev->pm.backend.shaders_state == KBASE_SHADERS_OFF_CORESTACK_OFF)
kbase_pm_l2_update_state(kbdev);
kbdev->pm.backend.shaders_state ==
KBASE_SHADERS_OFF_CORESTACK_OFF) {
if (kbase_pm_l2_update_state(kbdev))
return;
}
if (kbase_pm_is_in_desired_state_nolock(kbdev)) {
KBASE_TRACE_ADD(kbdev, PM_DESIRED_REACHED, NULL, NULL,
true, kbdev->pm.backend.shaders_avail);
KBASE_KTRACE_ADD(kbdev, PM_DESIRED_REACHED, NULL, kbdev->pm.backend.shaders_avail);
kbase_pm_trace_power_state(kbdev);
KBASE_TRACE_ADD(kbdev, PM_WAKE_WAITERS, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, PM_WAKE_WAITERS, NULL, 0);
wake_up(&kbdev->pm.backend.gpu_in_desired_state_wait);
}
}
@ -1555,7 +1589,7 @@ void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume)
kbdev->poweroff_pending = false;
KBASE_TRACE_ADD(kbdev, PM_GPU_ON, NULL, NULL, 0u, 0u);
KBASE_KTRACE_ADD(kbdev, PM_GPU_ON, NULL, 0u);
if (is_resume && kbdev->pm.backend.callback_power_resume) {
kbdev->pm.backend.callback_power_resume(kbdev);
@ -1580,6 +1614,15 @@ void kbase_pm_clock_on(struct kbase_device *kbdev, bool is_resume)
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
mutex_unlock(&kbdev->mmu_hw_mutex);
if (kbdev->dummy_job_wa.flags &
KBASE_DUMMY_JOB_WA_FLAG_LOGICAL_SHADER_POWER) {
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
kbase_dummy_job_wa_execute(kbdev,
kbase_pm_get_present_cores(kbdev,
KBASE_PM_CORE_SHADER));
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
}
/* Enable the interrupts */
kbase_pm_enable_interrupts(kbdev);
@ -1609,7 +1652,7 @@ bool kbase_pm_clock_off(struct kbase_device *kbdev)
return true;
}
KBASE_TRACE_ADD(kbdev, PM_GPU_OFF, NULL, NULL, 0u, 0u);
KBASE_KTRACE_ADD(kbdev, PM_GPU_OFF, NULL, 0u);
/* Disable interrupts. This also clears any outstanding interrupts */
kbase_pm_disable_interrupts(kbdev);
@ -1630,6 +1673,9 @@ bool kbase_pm_clock_off(struct kbase_device *kbdev)
/* The GPU power may be turned off from this point */
kbdev->pm.backend.gpu_powered = false;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
#ifdef CONFIG_MALI_ARBITER_SUPPORT
kbase_arbiter_pm_vm_event(kbdev, KBASE_VM_GPU_IDLE_EVENT);
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
if (kbdev->pm.backend.callback_power_off)
kbdev->pm.backend.callback_power_off(kbdev);
@ -1683,10 +1729,11 @@ static enum hrtimer_restart kbasep_reset_timeout(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
static void kbase_set_jm_quirks(struct kbase_device *kbdev, const u32 prod_id)
static int kbase_set_jm_quirks(struct kbase_device *kbdev, const u32 prod_id)
{
kbdev->hw_quirks_jm = kbase_reg_read(kbdev,
u32 hw_quirks_jm = kbase_reg_read(kbdev,
GPU_CONTROL_REG(JM_CONFIG));
if (GPU_ID2_MODEL_MATCH_VALUE(prod_id) == GPU_ID2_PRODUCT_TMIX) {
/* Only for tMIx */
u32 coherency_features;
@ -1699,11 +1746,17 @@ static void kbase_set_jm_quirks(struct kbase_device *kbdev, const u32 prod_id)
*/
if (coherency_features ==
COHERENCY_FEATURE_BIT(COHERENCY_ACE)) {
kbdev->hw_quirks_jm |= (COHERENCY_ACE_LITE |
hw_quirks_jm |= (COHERENCY_ACE_LITE |
COHERENCY_ACE) <<
JM_FORCE_COHERENCY_FEATURES_SHIFT;
}
}
if (kbase_is_gpu_lost(kbdev))
return -EIO;
kbdev->hw_quirks_jm = hw_quirks_jm;
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_IDVS_GROUP_SIZE)) {
int default_idvs_group_size = 0xF;
u32 tmp;
@ -1712,53 +1765,71 @@ static void kbase_set_jm_quirks(struct kbase_device *kbdev, const u32 prod_id)
"idvs-group-size", &tmp))
tmp = default_idvs_group_size;
if (tmp > JM_MAX_IDVS_GROUP_SIZE) {
if (tmp > IDVS_GROUP_MAX_SIZE) {
dev_err(kbdev->dev,
"idvs-group-size of %d is too large. Maximum value is %d",
tmp, JM_MAX_IDVS_GROUP_SIZE);
tmp, IDVS_GROUP_MAX_SIZE);
tmp = default_idvs_group_size;
}
kbdev->hw_quirks_jm |= tmp << JM_IDVS_GROUP_SIZE_SHIFT;
kbdev->hw_quirks_jm |= tmp << IDVS_GROUP_SIZE_SHIFT;
}
#define MANUAL_POWER_CONTROL ((u32)(1 << 8))
if (corestack_driver_control)
kbdev->hw_quirks_jm |= MANUAL_POWER_CONTROL;
return 0;
}
static void kbase_set_sc_quirks(struct kbase_device *kbdev, const u32 prod_id)
static int kbase_set_sc_quirks(struct kbase_device *kbdev, const u32 prod_id)
{
kbdev->hw_quirks_sc = kbase_reg_read(kbdev,
u32 hw_quirks_sc = kbase_reg_read(kbdev,
GPU_CONTROL_REG(SHADER_CONFIG));
if (kbase_is_gpu_lost(kbdev))
return -EIO;
if (prod_id < 0x750 || prod_id == 0x6956) /* T60x, T62x, T72x */
kbdev->hw_quirks_sc |= SC_LS_ATTR_CHECK_DISABLE;
hw_quirks_sc |= SC_LS_ATTR_CHECK_DISABLE;
else if (prod_id >= 0x750 && prod_id <= 0x880) /* T76x, T8xx */
kbdev->hw_quirks_sc |= SC_LS_ALLOW_ATTR_TYPES;
hw_quirks_sc |= SC_LS_ALLOW_ATTR_TYPES;
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TTRX_2968_TTRX_3162))
kbdev->hw_quirks_sc |= SC_VAR_ALGORITHM;
hw_quirks_sc |= SC_VAR_ALGORITHM;
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_TLS_HASHING))
kbdev->hw_quirks_sc |= SC_TLS_HASH_ENABLE;
hw_quirks_sc |= SC_TLS_HASH_ENABLE;
kbdev->hw_quirks_sc = hw_quirks_sc;
return 0;
}
static void kbase_set_tiler_quirks(struct kbase_device *kbdev)
static int kbase_set_tiler_quirks(struct kbase_device *kbdev)
{
kbdev->hw_quirks_tiler = kbase_reg_read(kbdev,
u32 hw_quirks_tiler = kbase_reg_read(kbdev,
GPU_CONTROL_REG(TILER_CONFIG));
if (kbase_is_gpu_lost(kbdev))
return -EIO;
/* Set tiler clock gate override if required */
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_T76X_3953))
kbdev->hw_quirks_tiler |= TC_CLOCK_GATE_OVERRIDE;
hw_quirks_tiler |= TC_CLOCK_GATE_OVERRIDE;
kbdev->hw_quirks_tiler = hw_quirks_tiler;
return 0;
}
static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
static int kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
{
struct device_node *np = kbdev->dev->of_node;
const u32 gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
const u32 prod_id = (gpu_id & GPU_ID_VERSION_PRODUCT_ID) >>
GPU_ID_VERSION_PRODUCT_ID_SHIFT;
int error = 0;
kbdev->hw_quirks_jm = 0;
kbdev->hw_quirks_sc = 0;
@ -1771,7 +1842,9 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
"Found quirks_jm = [0x%x] in Devicetree\n",
kbdev->hw_quirks_jm);
} else {
kbase_set_jm_quirks(kbdev, prod_id);
error = kbase_set_jm_quirks(kbdev, prod_id);
if (error)
return error;
}
if (!of_property_read_u32(np, "quirks_sc",
@ -1780,7 +1853,9 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
"Found quirks_sc = [0x%x] in Devicetree\n",
kbdev->hw_quirks_sc);
} else {
kbase_set_sc_quirks(kbdev, prod_id);
error = kbase_set_sc_quirks(kbdev, prod_id);
if (error)
return error;
}
if (!of_property_read_u32(np, "quirks_tiler",
@ -1789,7 +1864,9 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
"Found quirks_tiler = [0x%x] in Devicetree\n",
kbdev->hw_quirks_tiler);
} else {
kbase_set_tiler_quirks(kbdev);
error = kbase_set_tiler_quirks(kbdev);
if (error)
return error;
}
if (!of_property_read_u32(np, "quirks_mmu",
@ -1798,8 +1875,10 @@ static void kbase_pm_hw_issues_detect(struct kbase_device *kbdev)
"Found quirks_mmu = [0x%x] in Devicetree\n",
kbdev->hw_quirks_mmu);
} else {
kbase_set_mmu_quirks(kbdev);
error = kbase_set_mmu_quirks(kbdev);
}
return error;
}
static void kbase_pm_hw_issues_apply(struct kbase_device *kbdev)
@ -1861,7 +1940,7 @@ static int kbase_pm_do_reset(struct kbase_device *kbdev)
struct kbasep_reset_timeout_data rtdata;
int ret;
KBASE_TRACE_ADD(kbdev, CORE_GPU_SOFT_RESET, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_SOFT_RESET, NULL, 0);
KBASE_TLSTREAM_JD_GPU_SOFT_RESET(kbdev, kbdev);
@ -1902,8 +1981,9 @@ static int kbase_pm_do_reset(struct kbase_device *kbdev)
/* No interrupt has been received - check if the RAWSTAT register says
* the reset has completed */
if (kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) &
RESET_COMPLETED) {
if ((kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_RAWSTAT)) &
RESET_COMPLETED)
|| kbase_is_gpu_lost(kbdev)) {
/* The interrupt is set in the RAWSTAT; this suggests that the
* interrupts are not getting to the CPU */
dev_err(kbdev->dev, "Reset interrupt didn't reach CPU. Check interrupt assignments.\n");
@ -1916,7 +1996,7 @@ static int kbase_pm_do_reset(struct kbase_device *kbdev)
* reset */
dev_err(kbdev->dev, "Failed to soft-reset GPU (timed out after %d ms), now attempting a hard reset\n",
RESET_TIMEOUT);
KBASE_TRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, NULL, 0u, 0);
KBASE_KTRACE_ADD(kbdev, CORE_GPU_HARD_RESET, NULL, 0);
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_HARD_RESET);
@ -1944,29 +2024,20 @@ static int kbase_pm_do_reset(struct kbase_device *kbdev)
return -EINVAL;
}
static int kbasep_protected_mode_enable(struct protected_mode_device *pdev)
int kbase_pm_protected_mode_enable(struct kbase_device *const kbdev)
{
struct kbase_device *kbdev = pdev->data;
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_COMMAND),
GPU_COMMAND_SET_PROTECTED_MODE);
return 0;
}
static int kbasep_protected_mode_disable(struct protected_mode_device *pdev)
int kbase_pm_protected_mode_disable(struct kbase_device *const kbdev)
{
struct kbase_device *kbdev = pdev->data;
lockdep_assert_held(&kbdev->pm.lock);
return kbase_pm_do_reset(kbdev);
}
struct protected_mode_ops kbase_native_protected_ops = {
.protected_mode_enable = kbasep_protected_mode_enable,
.protected_mode_disable = kbasep_protected_mode_disable
};
int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags)
{
unsigned long irq_flags;
@ -1994,16 +2065,12 @@ int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags)
/* The cores should be made unavailable due to the reset */
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
if (kbdev->pm.backend.shaders_state != KBASE_SHADERS_OFF_CORESTACK_OFF)
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL,
NULL, 0u, (u32)0u);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_AVAILABLE, NULL, 0u);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, irq_flags);
/* Soft reset the GPU */
if (kbdev->protected_mode_support)
err = kbdev->protected_ops->protected_mode_disable(
kbdev->protected_dev);
else
err = kbase_pm_do_reset(kbdev);
err = kbdev->protected_ops->protected_mode_disable(
kbdev->protected_dev);
spin_lock_irqsave(&kbdev->hwaccess_lock, irq_flags);
kbdev->protected_mode = false;
@ -2012,19 +2079,18 @@ int kbase_pm_init_hw(struct kbase_device *kbdev, unsigned int flags)
if (err)
goto exit;
if (flags & PM_HW_ISSUES_DETECT)
kbase_pm_hw_issues_detect(kbdev);
if (flags & PM_HW_ISSUES_DETECT) {
err = kbase_pm_hw_issues_detect(kbdev);
if (err)
goto exit;
}
kbase_pm_hw_issues_apply(kbdev);
kbase_cache_set_coherency_mode(kbdev, kbdev->system_coherency);
/* Sanity check protected mode was left after reset */
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_PROTECTED_MODE)) {
u32 gpu_status = kbase_reg_read(kbdev,
GPU_CONTROL_REG(GPU_STATUS));
WARN_ON(gpu_status & GPU_STATUS_PROTECTED_MODE_ACTIVE);
}
WARN_ON(kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_STATUS)) &
GPU_STATUS_PROTECTED_MODE_ACTIVE);
/* If cycle counter was in use re-enable it, enable_irqs will only be
* false when called from kbase_pm_powerup */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -682,4 +682,29 @@ extern bool corestack_driver_control;
* Return: true if l2 need to power on
*/
bool kbase_pm_is_l2_desired(struct kbase_device *kbdev);
/**
* kbase_pm_lock - Lock all necessary mutexes to perform PM actions
*
* @kbdev: Device pointer
*
* This function locks correct mutexes independent of GPU architecture.
*/
static inline void kbase_pm_lock(struct kbase_device *kbdev)
{
mutex_lock(&kbdev->js_data.runpool_mutex);
mutex_lock(&kbdev->pm.lock);
}
/**
* kbase_pm_unlock - Unlock mutexes locked by kbase_pm_lock
*
* @kbdev: Device pointer
*/
static inline void kbase_pm_unlock(struct kbase_device *kbdev)
{
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&kbdev->js_data.runpool_mutex);
}
#endif /* _KBASE_BACKEND_PM_INTERNAL_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -31,6 +31,7 @@
#include <backend/gpu/mali_kbase_pm_internal.h>
#include <backend/gpu/mali_kbase_jm_rb.h>
#include <backend/gpu/mali_kbase_pm_defs.h>
#include <mali_linux_trace.h>
/* When VSync is being hit aim for utilisation between 70-90% */
#define KBASE_PM_VSYNC_MIN_UTILISATION 70
@ -284,8 +285,11 @@ static void kbase_pm_metrics_active_calc(struct kbase_device *kbdev)
active_cl_ctx[device_nr] = 1;
} else {
kbdev->pm.backend.metrics.active_gl_ctx[js] = 1;
trace_sysgraph(SGR_ACTIVE, 0, js);
}
kbdev->pm.backend.metrics.gpu_active = true;
} else {
trace_sysgraph(SGR_INACTIVE, 0, js);
}
}
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -25,7 +25,7 @@
*/
#include <mali_kbase.h>
#include <mali_midg_regmap.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase_pm.h>
#include <backend/gpu/mali_kbase_pm_internal.h>
@ -102,6 +102,8 @@ void kbase_pm_update_active(struct kbase_device *kbdev)
* when there are contexts active */
KBASE_DEBUG_ASSERT(pm->active_count == 0);
pm->backend.poweron_required = false;
/* Request power off */
if (pm->backend.gpu_powered) {
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
@ -157,8 +159,7 @@ void kbase_pm_update_cores_state_nolock(struct kbase_device *kbdev)
shaders_desired = kbdev->pm.backend.pm_current_policy->shaders_needed(kbdev);
if (kbdev->pm.backend.shaders_desired != shaders_desired) {
KBASE_TRACE_ADD(kbdev, PM_CORES_CHANGE_DESIRED, NULL, NULL, 0u,
(u32)kbdev->pm.backend.shaders_desired);
KBASE_KTRACE_ADD(kbdev, PM_CORES_CHANGE_DESIRED, NULL, kbdev->pm.backend.shaders_desired);
kbdev->pm.backend.shaders_desired = shaders_desired;
kbase_pm_update_state(kbdev);
@ -199,22 +200,20 @@ 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);
KBASE_KTRACE_ADD(kbdev, PM_SET_POLICY, NULL, 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);
kbase_pm_lock(kbdev);
/* Remove the policy to prevent IRQ handlers from working on it */
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
@ -222,13 +221,11 @@ void kbase_pm_set_policy(struct kbase_device *kbdev,
kbdev->pm.backend.pm_current_policy = NULL;
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
KBASE_TRACE_ADD(kbdev, PM_CURRENT_POLICY_TERM, NULL, NULL, 0u,
old_policy->id);
KBASE_KTRACE_ADD(kbdev, PM_CURRENT_POLICY_TERM, NULL, 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);
KBASE_KTRACE_ADD(kbdev, PM_CURRENT_POLICY_INIT, NULL, new_policy->id);
if (new_policy->init)
new_policy->init(kbdev);
@ -242,8 +239,7 @@ void kbase_pm_set_policy(struct kbase_device *kbdev,
kbase_pm_update_active(kbdev);
kbase_pm_update_cores_state(kbdev);
mutex_unlock(&kbdev->pm.lock);
mutex_unlock(&js_devdata->runpool_mutex);
kbase_pm_unlock(kbdev);
/* Now the policy change is finished, we release our fake context active
* reference */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2018-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2016,2018-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016,2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -26,7 +26,7 @@
#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)
u64 *system_time, struct timespec64 *ts)
{
u32 hi1, hi2;
@ -60,7 +60,11 @@ void kbase_backend_get_gpu_time(struct kbase_device *kbdev, u64 *cycle_counter,
/* Record the CPU's idea of current time */
if (ts != NULL)
getrawmonotonic(ts);
#if (KERNEL_VERSION(4, 17, 0) > LINUX_VERSION_CODE)
*ts = ktime_to_timespec64(ktime_get_raw());
#else
ktime_get_raw_ts64(ts);
#endif
kbase_pm_release_gpu_cycle_counter(kbdev);
}

View File

@ -1,13 +1,16 @@
/*
* Copyright:
* ----------------------------------------------------------------------------
* This confidential and proprietary software may be used only as authorized
* by a licensing agreement from ARM Limited.
* (C) COPYRIGHT 2017-2019 ARM Limited, ALL RIGHTS RESERVED
* The entire notice above must be reproduced on all authorized copies and
* copies may only be made to the extent permitted by a licensing agreement
* from ARM Limited.
* ----------------------------------------------------------------------------
*
* (C) COPYRIGHT 2017-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
/* Kernel-side tests may include mali_kbase's headers. Therefore any config
@ -34,9 +37,6 @@ bob_defaults {
buslog: {
kbuild_options: ["CONFIG_MALI_BUSLOG=y"],
},
cinstr_job_dump: {
kbuild_options: ["CONFIG_MALI_JOB_DUMP=y"],
},
cinstr_vector_dump: {
kbuild_options: ["CONFIG_MALI_VECTOR_DUMP=y"],
},
@ -46,6 +46,9 @@ bob_defaults {
mali_gator_support: {
kbuild_options: ["CONFIG_MALI_BIFROST_GATOR_SUPPORT=y"],
},
mali_midgard_enable_trace: {
kbuild_options: ["CONFIG_MALI_BIFROST_ENABLE_TRACE=y"],
},
mali_system_trace: {
kbuild_options: ["CONFIG_MALI_BIFROST_SYSTEM_TRACE=y"],
},
@ -61,6 +64,12 @@ bob_defaults {
mali_dma_buf_legacy_compat: {
kbuild_options: ["CONFIG_MALI_DMA_BUF_LEGACY_COMPAT=y"],
},
mali_arbiter_support: {
kbuild_options: ["CONFIG_MALI_ARBITER_SUPPORT=y"],
},
mali_gem5_build: {
kbuild_options: ["CONFIG_MALI_GEM5_BUILD=y"],
},
kbuild_options: [
"MALI_UNIT_TEST={{.unit_test_code}}",
"MALI_CUSTOMER_RELEASE={{.release}}",
@ -79,6 +88,8 @@ bob_kernel_module {
"backend/gpu/*.c",
"backend/gpu/*.h",
"backend/gpu/Kbuild",
"context/*.c",
"context/*.h",
"ipa/*.c",
"ipa/*.h",
"ipa/Kbuild",
@ -87,6 +98,16 @@ bob_kernel_module {
"platform/*/*.h",
"platform/*/Kbuild",
"thirdparty/*.c",
"debug/*.c",
"debug/*.h",
"device/*.c",
"device/*.h",
"gpu/*.c",
"gpu/*.h",
"tl/*.c",
"tl/*.h",
"mmu/*.c",
"mmu/*.h",
],
kbuild_options: [
"CONFIG_MALI_KUTF=n",
@ -111,6 +132,9 @@ bob_kernel_module {
cinstr_secondary_hwc: {
kbuild_options: ["CONFIG_MALI_BIFROST_PRFCNT_SET_SECONDARY=y"],
},
cinstr_secondary_hwc_via_debug_fs: {
kbuild_options: ["CONFIG_MALI_PRFCNT_SET_SECONDARY_VIA_DEBUG_FS=y"],
},
mali_2mb_alloc: {
kbuild_options: ["CONFIG_MALI_2MB_ALLOC=y"],
},
@ -120,11 +144,39 @@ bob_kernel_module {
mali_hw_errata_1485982_use_clock_alternative: {
kbuild_options: ["CONFIG_MALI_HW_ERRATA_1485982_USE_CLOCK_ALTERNATIVE=y"],
},
gpu_has_job_manager: {
srcs: [
"context/backend/*_jm.c",
"debug/backend/*_jm.c",
"debug/backend/*_jm.h",
"device/backend/*_jm.c",
"gpu/backend/*_jm.c",
"gpu/backend/*_jm.h",
"jm/*.h",
"tl/backend/*_jm.c",
"mmu/backend/*_jm.c",
],
},
gpu_has_csf: {
srcs: [
"context/backend/*_csf.c",
"csf/*.c",
"csf/*.h",
"csf/Kbuild",
"debug/backend/*_csf.c",
"debug/backend/*_csf.h",
"device/backend/*_csf.c",
"gpu/backend/*_csf.c",
"gpu/backend/*_csf.h",
"tl/backend/*_csf.c",
"mmu/backend/*_csf.c",
],
},
mali_arbiter_support: {
srcs: [
"arbiter/*.c",
"arbiter/*.h",
"arbiter/Kbuild",
],
},
defaults: ["mali_kbase_shared_config_defaults"],

View File

@ -0,0 +1,213 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Base kernel context APIs for Job Manager GPUs
*/
#include <context/mali_kbase_context_internal.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase.h>
#include <mali_kbase_ctx_sched.h>
#include <mali_kbase_dma_fence.h>
#include <mali_kbase_mem_linux.h>
#include <mali_kbase_mem_pool_group.h>
#include <mmu/mali_kbase_mmu.h>
#include <tl/mali_kbase_timeline.h>
#include <tl/mali_kbase_tracepoints.h>
#ifdef CONFIG_DEBUG_FS
#include <mali_kbase_debug_mem_view.h>
#include <mali_kbase_mem_pool_debugfs.h>
void kbase_context_debugfs_init(struct kbase_context *const kctx)
{
kbase_debug_mem_view_init(kctx);
kbase_mem_pool_debugfs_init(kctx->kctx_dentry, kctx);
kbase_jit_debugfs_init(kctx);
kbasep_jd_debugfs_ctx_init(kctx);
kbase_debug_job_fault_context_init(kctx);
}
KBASE_EXPORT_SYMBOL(kbase_context_debugfs_init);
void kbase_context_debugfs_term(struct kbase_context *const kctx)
{
debugfs_remove_recursive(kctx->kctx_dentry);
kbase_debug_job_fault_context_term(kctx);
}
KBASE_EXPORT_SYMBOL(kbase_context_debugfs_term);
#else
void kbase_context_debugfs_init(struct kbase_context *const kctx)
{
CSTD_UNUSED(kctx);
}
KBASE_EXPORT_SYMBOL(kbase_context_debugfs_init);
void kbase_context_debugfs_term(struct kbase_context *const kctx)
{
CSTD_UNUSED(kctx);
}
KBASE_EXPORT_SYMBOL(kbase_context_debugfs_term);
#endif /* CONFIG_DEBUG_FS */
static int kbase_context_kbase_timer_setup(struct kbase_context *kctx)
{
kbase_timer_setup(&kctx->soft_job_timeout,
kbasep_soft_job_timeout_worker);
return 0;
}
static int kbase_context_submit_check(struct kbase_context *kctx)
{
struct kbasep_js_kctx_info *js_kctx_info = &kctx->jctx.sched_info;
unsigned long irq_flags = 0;
base_context_create_flags const flags = kctx->create_flags;
mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, irq_flags);
/* Translate the flags */
if ((flags & BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) == 0)
kbase_ctx_flag_clear(kctx, KCTX_SUBMIT_DISABLED);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, irq_flags);
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
return 0;
}
static const struct kbase_context_init context_init[] = {
{kbase_context_common_init, kbase_context_common_term, NULL},
{kbase_context_mem_pool_group_init, kbase_context_mem_pool_group_term,
"Memory pool goup initialization failed"},
{kbase_mem_evictable_init, kbase_mem_evictable_deinit,
"Memory evictable initialization failed"},
{kbasep_js_kctx_init, kbasep_js_kctx_term,
"JS kctx initialization failed"},
{kbase_jd_init, kbase_jd_exit,
"JD initialization failed"},
{kbase_event_init, kbase_event_cleanup,
"Event initialization failed"},
{kbase_dma_fence_init, kbase_dma_fence_term,
"DMA fence initialization failed"},
{kbase_context_mmu_init, kbase_context_mmu_term,
"MMU initialization failed"},
{kbase_context_mem_alloc_page, kbase_context_mem_pool_free,
"Memory alloc page failed"},
{kbase_region_tracker_init, kbase_region_tracker_term,
"Region tracker initialization failed"},
{kbase_sticky_resource_init, kbase_context_sticky_resource_term,
"Sticky resource initialization failed"},
{kbase_jit_init, kbase_jit_term,
"JIT initialization failed"},
{kbase_context_kbase_timer_setup, NULL, NULL},
{kbase_context_submit_check, NULL, NULL},
};
static void kbase_context_term_partial(
struct kbase_context *kctx,
unsigned int i)
{
while (i-- > 0) {
if (context_init[i].term)
context_init[i].term(kctx);
}
}
struct kbase_context *kbase_create_context(struct kbase_device *kbdev,
bool is_compat,
base_context_create_flags const flags,
unsigned long const api_version,
struct file *const filp)
{
struct kbase_context *kctx;
unsigned int i = 0;
if (WARN_ON(!kbdev))
return NULL;
/* Validate flags */
if (WARN_ON(flags != (flags & BASEP_CONTEXT_CREATE_KERNEL_FLAGS)))
return NULL;
/* zero-inited as lot of code assume it's zero'ed out on create */
kctx = vzalloc(sizeof(*kctx));
if (WARN_ON(!kctx))
return NULL;
kctx->kbdev = kbdev;
kctx->api_version = api_version;
kctx->filp = filp;
kctx->create_flags = flags;
if (is_compat)
kbase_ctx_flag_set(kctx, KCTX_COMPAT);
#if defined(CONFIG_64BIT)
else
kbase_ctx_flag_set(kctx, KCTX_FORCE_SAME_VA);
#endif /* !defined(CONFIG_64BIT) */
for (i = 0; i < ARRAY_SIZE(context_init); i++) {
int err = context_init[i].init(kctx);
if (err) {
dev_err(kbdev->dev, "%s error = %d\n",
context_init[i].err_mes, err);
kbase_context_term_partial(kctx, i);
return NULL;
}
}
return kctx;
}
KBASE_EXPORT_SYMBOL(kbase_create_context);
void kbase_destroy_context(struct kbase_context *kctx)
{
struct kbase_device *kbdev;
if (WARN_ON(!kctx))
return;
kbdev = kctx->kbdev;
if (WARN_ON(!kbdev))
return;
/* 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_mem_pool_group_mark_dying(&kctx->mem_pools);
kbase_jd_zap_context(kctx);
flush_workqueue(kctx->jctx.job_done_wq);
kbase_context_term_partial(kctx, ARRAY_SIZE(context_init));
kbase_pm_context_idle(kbdev);
}
KBASE_EXPORT_SYMBOL(kbase_destroy_context);

View File

@ -0,0 +1,210 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Base kernel context APIs
*/
#include <mali_kbase.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase_mem_linux.h>
#include <mali_kbase_dma_fence.h>
#include <mali_kbase_ctx_sched.h>
#include <mali_kbase_mem_pool_group.h>
#include <tl/mali_kbase_tracepoints.h>
#include <tl/mali_kbase_timeline.h>
#include <mmu/mali_kbase_mmu.h>
#include <context/mali_kbase_context_internal.h>
int kbase_context_common_init(struct kbase_context *kctx)
{
const unsigned long cookies_mask = KBASE_COOKIE_MASK;
/* creating a context is considered a disjoint event */
kbase_disjoint_event(kctx->kbdev);
kctx->as_nr = KBASEP_AS_NR_INVALID;
atomic_set(&kctx->refcount, 0);
spin_lock_init(&kctx->mm_update_lock);
kctx->process_mm = NULL;
atomic_set(&kctx->nonmapped_pages, 0);
atomic_set(&kctx->permanent_mapped_pages, 0);
kctx->tgid = current->tgid;
kctx->pid = current->pid;
atomic_set(&kctx->used_pages, 0);
mutex_init(&kctx->reg_lock);
spin_lock_init(&kctx->mem_partials_lock);
INIT_LIST_HEAD(&kctx->mem_partials);
spin_lock_init(&kctx->waiting_soft_jobs_lock);
INIT_LIST_HEAD(&kctx->waiting_soft_jobs);
init_waitqueue_head(&kctx->event_queue);
atomic_set(&kctx->event_count, 0);
atomic_set(&kctx->event_closed, false);
bitmap_copy(kctx->cookies, &cookies_mask, BITS_PER_LONG);
#ifdef CONFIG_GPU_TRACEPOINTS
atomic_set(&kctx->jctx.work_id, 0);
#endif
kctx->id = atomic_add_return(1, &(kctx->kbdev->ctx_num)) - 1;
mutex_init(&kctx->legacy_hwcnt_lock);
mutex_lock(&kctx->kbdev->kctx_list_lock);
list_add(&kctx->kctx_list_link, &kctx->kbdev->kctx_list);
KBASE_TLSTREAM_TL_KBASE_NEW_CTX(kctx->kbdev, kctx->id,
kctx->kbdev->gpu_props.props.raw_props.gpu_id);
KBASE_TLSTREAM_TL_NEW_CTX(kctx->kbdev, kctx, kctx->id,
(u32)(kctx->tgid));
mutex_unlock(&kctx->kbdev->kctx_list_lock);
return 0;
}
void kbase_context_common_term(struct kbase_context *kctx)
{
unsigned long flags;
int pages;
mutex_lock(&kctx->kbdev->mmu_hw_mutex);
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, flags);
kbase_ctx_sched_remove_ctx(kctx);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags);
mutex_unlock(&kctx->kbdev->mmu_hw_mutex);
pages = atomic_read(&kctx->used_pages);
if (pages != 0)
dev_warn(kctx->kbdev->dev,
"%s: %d pages in use!\n", __func__, pages);
WARN_ON(atomic_read(&kctx->nonmapped_pages) != 0);
mutex_lock(&kctx->kbdev->kctx_list_lock);
KBASE_TLSTREAM_TL_KBASE_DEL_CTX(kctx->kbdev, kctx->id);
KBASE_TLSTREAM_TL_DEL_CTX(kctx->kbdev, kctx);
list_del(&kctx->kctx_list_link);
mutex_unlock(&kctx->kbdev->kctx_list_lock);
KBASE_KTRACE_ADD(kctx->kbdev, CORE_CTX_DESTROY, kctx, 0u);
/* Flush the timeline stream, so the user can see the termination
* tracepoints being fired.
* The "if" statement below is for optimization. It is safe to call
* kbase_timeline_streams_flush when timeline is disabled.
*/
if (atomic_read(&kctx->kbdev->timeline_flags) != 0)
kbase_timeline_streams_flush(kctx->kbdev->timeline);
vfree(kctx);
}
int kbase_context_mem_pool_group_init(struct kbase_context *kctx)
{
return kbase_mem_pool_group_init(&kctx->mem_pools,
kctx->kbdev,
&kctx->kbdev->mem_pool_defaults,
&kctx->kbdev->mem_pools);
}
void kbase_context_mem_pool_group_term(struct kbase_context *kctx)
{
kbase_mem_pool_group_term(&kctx->mem_pools);
}
int kbase_context_mmu_init(struct kbase_context *kctx)
{
kbase_mmu_init(kctx->kbdev,
&kctx->mmu, kctx,
base_context_mmu_group_id_get(kctx->create_flags));
return 0;
}
void kbase_context_mmu_term(struct kbase_context *kctx)
{
kbase_mmu_term(kctx->kbdev, &kctx->mmu);
}
int kbase_context_mem_alloc_page(struct kbase_context *kctx)
{
struct page *p;
p = kbase_mem_alloc_page(&kctx->mem_pools.small[KBASE_MEM_GROUP_SINK]);
if (!p)
return -ENOMEM;
kctx->aliasing_sink_page = as_tagged(page_to_phys(p));
return 0;
}
void kbase_context_mem_pool_free(struct kbase_context *kctx)
{
/* drop the aliasing sink page now that it can't be mapped anymore */
kbase_mem_pool_free(
&kctx->mem_pools.small[KBASE_MEM_GROUP_SINK],
as_page(kctx->aliasing_sink_page),
false);
}
void kbase_context_sticky_resource_term(struct kbase_context *kctx)
{
unsigned long pending_regions_to_clean;
kbase_gpu_vm_lock(kctx);
kbase_sticky_resource_term(kctx);
/* free pending region setups */
pending_regions_to_clean = KBASE_COOKIE_MASK;
bitmap_andnot(&pending_regions_to_clean, &pending_regions_to_clean,
kctx->cookies, BITS_PER_LONG);
while (pending_regions_to_clean) {
unsigned int cookie = find_first_bit(&pending_regions_to_clean,
BITS_PER_LONG);
if (!WARN_ON(!kctx->pending_regions[cookie])) {
dev_dbg(kctx->kbdev->dev, "Freeing pending unmapped region\n");
kbase_mem_phy_alloc_put(
kctx->pending_regions[cookie]->cpu_alloc);
kbase_mem_phy_alloc_put(
kctx->pending_regions[cookie]->gpu_alloc);
kfree(kctx->pending_regions[cookie]);
kctx->pending_regions[cookie] = NULL;
}
bitmap_clear(&pending_regions_to_clean, cookie, 1);
}
kbase_gpu_vm_unlock(kctx);
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2017, 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -18,6 +18,16 @@
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2011-2017, 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
*/
#ifndef _KBASE_CONTEXT_H_
@ -25,6 +35,28 @@
#include <linux/atomic.h>
/**
* kbase_context_debugfs_init - Initialize the kctx platform
* specific debugfs
*
* @kctx: kbase context
*
* This initializes some debugfs interfaces specific to the platform the source
* is compiled for.
*/
void kbase_context_debugfs_init(struct kbase_context *const kctx);
/**
* kbase_context_debugfs_term - Terminate the kctx platform
* specific debugfs
*
* @kctx: kbase context
*
* This terminates some debugfs interfaces specific to the platform the source
* is compiled for.
*/
void kbase_context_debugfs_term(struct kbase_context *const kctx);
/**
* kbase_create_context() - Create a kernel base context.
*

View File

@ -0,0 +1,60 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*/
#include <mali_kbase.h>
typedef int kbase_context_init_method(struct kbase_context *kctx);
typedef void kbase_context_term_method(struct kbase_context *kctx);
/**
* struct kbase_context_init - Device init/term methods.
* @init: Function pointer to a initialise method.
* @term: Function pointer to a terminate method.
* @err_mes: Error message to be printed when init method fails.
*/
struct kbase_context_init {
kbase_context_init_method *init;
kbase_context_term_method *term;
char *err_mes;
};
int kbase_context_common_init(struct kbase_context *kctx);
void kbase_context_common_term(struct kbase_context *kctx);
int kbase_context_mem_pool_group_init(struct kbase_context *kctx);
void kbase_context_mem_pool_group_term(struct kbase_context *kctx);
int kbase_context_mmu_init(struct kbase_context *kctx);
void kbase_context_mmu_term(struct kbase_context *kctx);
int kbase_context_mem_alloc_page(struct kbase_context *kctx);
void kbase_context_mem_pool_free(struct kbase_context *kctx);
void kbase_context_sticky_resource_term(struct kbase_context *kctx);

View File

@ -0,0 +1,170 @@
/*
*
* (C) COPYRIGHT 2011-2015,2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* ***** IMPORTANT: THIS IS NOT A NORMAL HEADER FILE *****
* ***** DO NOT INCLUDE DIRECTLY *****
* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL *****
*/
/*
* The purpose of this header file is just to contain a list of trace code
* identifiers
*
* IMPORTANT: THIS FILE MUST NOT BE USED FOR ANY OTHER PURPOSE OTHER THAN THAT
* DESCRIBED IN mali_kbase_debug_ktrace_codes.h
*/
#if 0 /* Dummy section to avoid breaking formatting */
int dummy_array[] = {
#endif
/*
* Job Slot management events
*/
/* info_val==irq rawstat at start */
KBASE_KTRACE_CODE_MAKE_CODE(JM_IRQ),
/* info_val==jobs processed */
KBASE_KTRACE_CODE_MAKE_CODE(JM_IRQ_END),
/* In the following:
*
* - ctx is set if a corresponding job found (NULL otherwise, e.g. some
* soft-stop cases)
* - uatom==kernel-side mapped uatom address (for correlation with
* user-side)
*/
/* info_val==exit code; gpu_addr==chain gpuaddr */
KBASE_KTRACE_CODE_MAKE_CODE(JM_JOB_DONE),
/* gpu_addr==JS_HEAD_NEXT written, info_val==lower 32 bits of
* affinity
*/
KBASE_KTRACE_CODE_MAKE_CODE(JM_SUBMIT),
/* gpu_addr is as follows:
* - If JS_STATUS active after soft-stop, val==gpu addr written to
* JS_HEAD on submit
* - otherwise gpu_addr==0
*/
KBASE_KTRACE_CODE_MAKE_CODE(JM_SOFTSTOP),
KBASE_KTRACE_CODE_MAKE_CODE(JM_SOFTSTOP_0),
KBASE_KTRACE_CODE_MAKE_CODE(JM_SOFTSTOP_1),
/* gpu_addr==JS_HEAD read */
KBASE_KTRACE_CODE_MAKE_CODE(JM_HARDSTOP),
/* gpu_addr==JS_HEAD read */
KBASE_KTRACE_CODE_MAKE_CODE(JM_HARDSTOP_0),
/* gpu_addr==JS_HEAD read */
KBASE_KTRACE_CODE_MAKE_CODE(JM_HARDSTOP_1),
/* gpu_addr==JS_TAIL read */
KBASE_KTRACE_CODE_MAKE_CODE(JM_UPDATE_HEAD),
/* gpu_addr is as follows:
* - If JS_STATUS active before soft-stop, val==JS_HEAD
* - otherwise gpu_addr==0
*/
/* gpu_addr==JS_HEAD read */
KBASE_KTRACE_CODE_MAKE_CODE(JM_CHECK_HEAD),
KBASE_KTRACE_CODE_MAKE_CODE(JM_FLUSH_WORKQS),
KBASE_KTRACE_CODE_MAKE_CODE(JM_FLUSH_WORKQS_DONE),
/* info_val == is_scheduled */
KBASE_KTRACE_CODE_MAKE_CODE(JM_ZAP_NON_SCHEDULED),
/* info_val == is_scheduled */
KBASE_KTRACE_CODE_MAKE_CODE(JM_ZAP_SCHEDULED),
KBASE_KTRACE_CODE_MAKE_CODE(JM_ZAP_DONE),
/* info_val == nr jobs submitted */
KBASE_KTRACE_CODE_MAKE_CODE(JM_SLOT_SOFT_OR_HARD_STOP),
/* gpu_addr==JS_HEAD_NEXT last written */
KBASE_KTRACE_CODE_MAKE_CODE(JM_SLOT_EVICT),
KBASE_KTRACE_CODE_MAKE_CODE(JM_SUBMIT_AFTER_RESET),
KBASE_KTRACE_CODE_MAKE_CODE(JM_BEGIN_RESET_WORKER),
KBASE_KTRACE_CODE_MAKE_CODE(JM_END_RESET_WORKER),
/*
* Job dispatch events
*/
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_DONE),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_DONE_WORKER),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_DONE_WORKER_END),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_DONE_TRY_RUN_NEXT_JOB),
/* gpu_addr==0, info_val==0, uatom==0 */
KBASE_KTRACE_CODE_MAKE_CODE(JD_ZAP_CONTEXT),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_CANCEL),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JD_CANCEL_WORKER),
/*
* Scheduler Core events
*/
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JS_ADD_JOB),
/* gpu_addr==last value written/would be written to JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JS_REMOVE_JOB),
KBASE_KTRACE_CODE_MAKE_CODE(JS_TRY_SCHEDULE_HEAD_CTX),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JS_JOB_DONE_TRY_RUN_NEXT_JOB),
/* gpu_addr==value to write into JS_HEAD */
KBASE_KTRACE_CODE_MAKE_CODE(JS_JOB_DONE_RETRY_NEEDED),
KBASE_KTRACE_CODE_MAKE_CODE(JS_AFFINITY_SUBMIT_TO_BLOCKED),
/* info_val == lower 32 bits of affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_AFFINITY_CURRENT),
/* info_val == lower 32 bits of affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CORE_REF_REQUEST_CORES_FAILED),
/* info_val == lower 32 bits of affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CORE_REF_REGISTER_INUSE_FAILED),
/* info_val == lower 32 bits of rechecked affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CORE_REF_REQUEST_ON_RECHECK_FAILED),
/* info_val == lower 32 bits of rechecked affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CORE_REF_REGISTER_ON_RECHECK_FAILED),
/* info_val == lower 32 bits of affinity */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CORE_REF_AFFINITY_WOULD_VIOLATE),
/* info_val == the ctx attribute now on ctx */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_ON_CTX),
/* info_val == the ctx attribute now on runpool */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_ON_RUNPOOL),
/* info_val == the ctx attribute now off ctx */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_OFF_CTX),
/* info_val == the ctx attribute now off runpool */
KBASE_KTRACE_CODE_MAKE_CODE(JS_CTX_ATTR_NOW_OFF_RUNPOOL),
/*
* Scheduler Policy events
*/
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_INIT_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_TERM_CTX),
/* info_val == whether it was evicted */
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_TRY_EVICT_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_FOREACH_CTX_JOBS),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_ENQUEUE_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_HEAD_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_RUNPOOL_ADD_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_RUNPOOL_REMOVE_CTX),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_JOB),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_DEQUEUE_JOB_IRQ),
/* gpu_addr==JS_HEAD to write if the job were run */
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_ENQUEUE_JOB),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_TIMER_START),
KBASE_KTRACE_CODE_MAKE_CODE(JS_POLICY_TIMER_END),
#if 0 /* Dummy section to avoid breaking formatting */
};
#endif
/* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */

View File

@ -0,0 +1,75 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_DEBUG_KTRACE_DEFS_JM_H_
#define _KBASE_DEBUG_KTRACE_DEFS_JM_H_
/**
* DOC: KTrace version history, JM variant
* 1.0:
* - Original version (implicit, header did not carry version information)
* 2.0:
* - Introduced version information into the header
* - some changes of parameter names in header
* - trace now uses all 64-bits of info_val
* - Non-JM specific parts moved to using info_val instead of refcount/gpu_addr
*/
#define KBASE_KTRACE_VERSION_MAJOR 2
#define KBASE_KTRACE_VERSION_MINOR 0
/* indicates if the trace message has a valid refcount member */
#define KBASE_KTRACE_FLAG_JM_REFCOUNT (((kbase_ktrace_flag_t)1) << 0)
/* indicates if the trace message has a valid jobslot member */
#define KBASE_KTRACE_FLAG_JM_JOBSLOT (((kbase_ktrace_flag_t)1) << 1)
/* indicates if the trace message has valid atom related info. */
#define KBASE_KTRACE_FLAG_JM_ATOM (((kbase_ktrace_flag_t)1) << 2)
/**
* struct kbase_ktrace_backend - backend specific part of a trace message
*
* @atom_udata: Copy of the user data sent for the atom in base_jd_submit.
* Only valid if KBASE_KTRACE_FLAG_JM_ATOM is set in @flags
* @gpu_addr: GPU address, usually of the job-chain represented by an atom.
* @atom_number: id of the atom for which trace message was added. Only valid
* if KBASE_KTRACE_FLAG_JM_ATOM is set in @flags
* @code: Identifies the event, refer to enum kbase_ktrace_code.
* @flags: indicates information about the trace message itself. Used
* during dumping of the message.
* @jobslot: job-slot for which trace message was added, valid only for
* job-slot management events.
* @refcount: reference count for the context, valid for certain events
* related to scheduler core and policy.
*/
struct kbase_ktrace_backend {
/* Place 64 and 32-bit members together */
u64 atom_udata[2]; /* Only valid for KBASE_KTRACE_FLAG_JM_ATOM */
u64 gpu_addr;
int atom_number; /* Only valid for KBASE_KTRACE_FLAG_JM_ATOM */
/* Pack smaller members together */
kbase_ktrace_code_t code;
kbase_ktrace_flag_t flags;
u8 jobslot;
u8 refcount;
};
#endif /* _KBASE_DEBUG_KTRACE_DEFS_JM_H_ */

View File

@ -0,0 +1,113 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <mali_kbase.h>
#include "debug/mali_kbase_debug_ktrace_internal.h"
#include "debug/backend/mali_kbase_debug_ktrace_jm.h"
#if KBASE_KTRACE_TARGET_RBUF
void kbasep_ktrace_backend_format_header(char *buffer, int sz, s32 *written)
{
*written += MAX(snprintf(buffer + *written, MAX(sz - *written, 0),
"katom,gpu_addr,jobslot,refcount"), 0);
}
void kbasep_ktrace_backend_format_msg(struct kbase_ktrace_msg *trace_msg,
char *buffer, int sz, s32 *written)
{
/* katom */
if (trace_msg->backend.flags & KBASE_KTRACE_FLAG_JM_ATOM)
*written += MAX(snprintf(buffer + *written,
MAX(sz - *written, 0),
"atom %d (ud: 0x%llx 0x%llx)",
trace_msg->backend.atom_number,
trace_msg->backend.atom_udata[0],
trace_msg->backend.atom_udata[1]), 0);
/* gpu_addr */
if (trace_msg->backend.flags & KBASE_KTRACE_FLAG_BACKEND)
*written += MAX(snprintf(buffer + *written,
MAX(sz - *written, 0),
",%.8llx,", trace_msg->backend.gpu_addr), 0);
else
*written += MAX(snprintf(buffer + *written,
MAX(sz - *written, 0),
",,"), 0);
/* jobslot */
if (trace_msg->backend.flags & KBASE_KTRACE_FLAG_JM_JOBSLOT)
*written += MAX(snprintf(buffer + *written,
MAX(sz - *written, 0),
"%d", trace_msg->backend.jobslot), 0);
*written += MAX(snprintf(buffer + *written, MAX(sz - *written, 0),
","), 0);
/* refcount */
if (trace_msg->backend.flags & KBASE_KTRACE_FLAG_JM_REFCOUNT)
*written += MAX(snprintf(buffer + *written,
MAX(sz - *written, 0),
"%d", trace_msg->backend.refcount), 0);
}
void kbasep_ktrace_add_jm(struct kbase_device *kbdev,
enum kbase_ktrace_code code, struct kbase_context *kctx,
struct kbase_jd_atom *katom, u64 gpu_addr,
kbase_ktrace_flag_t flags, int refcount, int jobslot,
u64 info_val)
{
unsigned long irqflags;
struct kbase_ktrace_msg *trace_msg;
spin_lock_irqsave(&kbdev->ktrace.lock, irqflags);
/* Reserve and update indices */
trace_msg = kbasep_ktrace_reserve(&kbdev->ktrace);
/* Fill the common part of the message (including backend.flags) */
kbasep_ktrace_msg_init(&kbdev->ktrace, trace_msg, code, kctx, flags,
info_val);
/* Indicate to the common code that backend-specific parts will be
* valid
*/
trace_msg->backend.flags |= KBASE_KTRACE_FLAG_BACKEND;
/* Fill the JM-specific parts of the message */
if (katom) {
trace_msg->backend.flags |= KBASE_KTRACE_FLAG_JM_ATOM;
trace_msg->backend.atom_number = kbase_jd_atom_id(katom->kctx, katom);
trace_msg->backend.atom_udata[0] = katom->udata.blob[0];
trace_msg->backend.atom_udata[1] = katom->udata.blob[1];
}
trace_msg->backend.gpu_addr = gpu_addr;
trace_msg->backend.jobslot = jobslot;
/* Clamp refcount */
trace_msg->backend.refcount = MIN((unsigned int)refcount, 0xFF);
/* Done */
spin_unlock_irqrestore(&kbdev->ktrace.lock, irqflags);
}
#endif /* KBASE_KTRACE_TARGET_RBUF */

View File

@ -0,0 +1,362 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_DEBUG_KTRACE_JM_H_
#define _KBASE_DEBUG_KTRACE_JM_H_
/*
* KTrace target for internal ringbuffer
*/
#if KBASE_KTRACE_TARGET_RBUF
/**
* kbasep_ktrace_add_jm - internal function to add trace about Job Management
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @flags: flags about the message
* @refcount: reference count information to add to the trace
* @jobslot: jobslot information to add to the trace
* @info_val: generic information about @code to add to the trace
*
* PRIVATE: do not use directly. Use KBASE_KTRACE_ADD_JM() instead.
*/
void kbasep_ktrace_add_jm(struct kbase_device *kbdev,
enum kbase_ktrace_code code, struct kbase_context *kctx,
struct kbase_jd_atom *katom, u64 gpu_addr,
kbase_ktrace_flag_t flags, int refcount, int jobslot,
u64 info_val);
#define KBASE_KTRACE_RBUF_ADD_JM_SLOT(kbdev, code, kctx, katom, gpu_addr, \
jobslot) \
kbasep_ktrace_add_jm(kbdev, KBASE_KTRACE_CODE(code), kctx, katom, \
gpu_addr, KBASE_KTRACE_FLAG_JM_JOBSLOT, 0, jobslot, 0)
#define KBASE_KTRACE_RBUF_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, gpu_addr, \
jobslot, info_val) \
kbasep_ktrace_add_jm(kbdev, KBASE_KTRACE_CODE(code), kctx, katom, \
gpu_addr, KBASE_KTRACE_FLAG_JM_JOBSLOT, 0, jobslot, \
info_val)
#define KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, gpu_addr, \
refcount) \
kbasep_ktrace_add_jm(kbdev, KBASE_KTRACE_CODE(code), kctx, katom, \
gpu_addr, KBASE_KTRACE_FLAG_JM_REFCOUNT, refcount, 0, 0)
#define KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT_INFO(kbdev, code, kctx, katom, \
gpu_addr, refcount, info_val) \
kbasep_ktrace_add_jm(kbdev, KBASE_KTRACE_CODE(code), kctx, katom, \
gpu_addr, KBASE_KTRACE_FLAG_JM_REFCOUNT, refcount, 0, \
info_val)
#define KBASE_KTRACE_RBUF_ADD_JM(kbdev, code, kctx, katom, gpu_addr, info_val) \
kbasep_ktrace_add_jm(kbdev, KBASE_KTRACE_CODE(code), kctx, katom, \
gpu_addr, 0, 0, 0, info_val)
#else /* KBASE_KTRACE_TARGET_RBUF */
#define KBASE_KTRACE_RBUF_ADD_JM_SLOT(kbdev, code, kctx, katom, gpu_addr, \
jobslot) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(jobslot);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_RBUF_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, gpu_addr, \
jobslot, info_val) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(jobslot);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, gpu_addr, \
refcount) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(refcount);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT_INFO(kbdev, code, kctx, katom, \
gpu_addr, refcount, info_val) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_RBUF_ADD_JM(kbdev, code, kctx, katom, gpu_addr, \
info_val)\
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#endif /* KBASE_KTRACE_TARGET_RBUF */
/*
* KTrace target for Linux's ftrace
*/
#if KBASE_KTRACE_TARGET_FTRACE
#define KBASE_KTRACE_FTRACE_ADD_JM_SLOT(kbdev, code, kctx, katom, gpu_addr, \
jobslot) \
trace_mali_##code(jobslot, 0)
#define KBASE_KTRACE_FTRACE_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, \
gpu_addr, jobslot, info_val) \
trace_mali_##code(jobslot, info_val)
#define KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, \
gpu_addr, refcount) \
trace_mali_##code(refcount, 0)
#define KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT_INFO(kbdev, code, kctx, katom, \
gpu_addr, refcount, info_val) \
trace_mali_##code(refcount, info_val)
#define KBASE_KTRACE_FTRACE_ADD_JM(kbdev, code, kctx, katom, gpu_addr, \
info_val) \
trace_mali_##code(gpu_addr, info_val)
#else /* KBASE_KTRACE_TARGET_FTRACE */
#define KBASE_KTRACE_FTRACE_ADD_JM_SLOT(kbdev, code, kctx, katom, gpu_addr, \
jobslot) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(jobslot);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_FTRACE_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, \
gpu_addr, jobslot, info_val) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(jobslot);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, \
gpu_addr, refcount) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(refcount);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT_INFO(kbdev, code, kctx, katom, \
gpu_addr, refcount, info_val) \
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#define KBASE_KTRACE_FTRACE_ADD_JM(kbdev, code, kctx, katom, gpu_addr, \
info_val)\
do {\
CSTD_UNUSED(kbdev);\
CSTD_NOP(code);\
CSTD_UNUSED(kctx);\
CSTD_UNUSED(katom);\
CSTD_UNUSED(gpu_addr);\
CSTD_UNUSED(info_val);\
CSTD_NOP(0);\
} while (0)
#endif /* KBASE_KTRACE_TARGET_FTRACE */
/*
* Master set of macros to route KTrace to any of the targets
*/
/**
* KBASE_KTRACE_ADD_JM_SLOT - Add trace values about a job-slot
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @jobslot: jobslot information to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD_JM_SLOT(kbdev, code, kctx, katom, gpu_addr, \
jobslot) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __gpu_addr = gpu_addr; \
int __jobslot = jobslot; \
KBASE_KTRACE_RBUF_ADD_JM_SLOT(kbdev, code, kctx, katom, __gpu_addr, __jobslot); \
KBASE_KTRACE_FTRACE_ADD_JM_SLOT(kbdev, code, kctx, katom, __gpu_addr, __jobslot); \
} while (0)
/**
* KBASE_KTRACE_ADD_JM_SLOT_INFO - Add trace values about a job-slot, with info
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @jobslot: jobslot information to add to the trace
* @info_val: generic information about @code to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, gpu_addr, \
jobslot, info_val) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __gpu_addr = gpu_addr; \
int __jobslot = jobslot; \
u64 __info_val = info_val; \
KBASE_KTRACE_RBUF_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, __gpu_addr, __jobslot, __info_val); \
KBASE_KTRACE_FTRACE_ADD_JM_SLOT_INFO(kbdev, code, kctx, katom, __gpu_addr, __jobslot, __info_val); \
} while (0)
/**
* KBASE_KTRACE_ADD_JM_REFCOUNT - Add trace values about a kctx refcount
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @refcount: reference count information to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, gpu_addr, \
refcount) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __gpu_addr = gpu_addr; \
int __refcount = refcount; \
KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, __gpu_addr, __refcount); \
KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, __gpu_addr, __refcount); \
} while (0)
/**
* KBASE_KTRACE_ADD_JM_REFCOUNT_INFO - Add trace values about a kctx refcount,
* and info
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @refcount: reference count information to add to the trace
* @info_val: generic information about @code to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD_JM_REFCOUNT_INFO(kbdev, code, kctx, katom, \
gpu_addr, refcount, info_val) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __gpu_addr = gpu_addr; \
int __refcount = refcount; \
u64 __info_val = info_val; \
KBASE_KTRACE_RBUF_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, __gpu_addr, __refcount, __info_val); \
KBASE_KTRACE_FTRACE_ADD_JM_REFCOUNT(kbdev, code, kctx, katom, __gpu_addr, __refcount, __info_val); \
} while (0)
/**
* KBASE_KTRACE_ADD_JM - Add trace values (no slot or refcount)
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @katom: kbase atom, or NULL if no atom
* @gpu_addr: GPU address, usually related to @katom
* @info_val: generic information about @code to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD_JM(kbdev, code, kctx, katom, gpu_addr, info_val) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __gpu_addr = gpu_addr; \
u64 __info_val = info_val; \
KBASE_KTRACE_RBUF_ADD_JM(kbdev, code, kctx, katom, __gpu_addr, __info_val); \
KBASE_KTRACE_FTRACE_ADD_JM(kbdev, code, kctx, katom, __gpu_addr, __info_val); \
} while (0)
#endif /* _KBASE_DEBUG_KTRACE_JM_H_ */

View File

@ -0,0 +1,150 @@
/*
*
* (C) COPYRIGHT 2014,2018,2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* NOTE: This must **only** be included through mali_linux_trace.h,
* otherwise it will fail to setup tracepoints correctly
*/
#if !defined(_KBASE_DEBUG_LINUX_KTRACE_JM_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _KBASE_DEBUG_LINUX_KTRACE_JM_H_
DECLARE_EVENT_CLASS(mali_jm_slot_template,
TP_PROTO(int jobslot, u64 info_val),
TP_ARGS(jobslot, info_val),
TP_STRUCT__entry(
__field(unsigned int, jobslot)
__field(u64, info_val)
),
TP_fast_assign(
__entry->jobslot = jobslot;
__entry->info_val = info_val;
),
TP_printk("jobslot=%u info=0x%llx", __entry->jobslot, __entry->info_val)
);
#define DEFINE_MALI_JM_SLOT_EVENT(name) \
DEFINE_EVENT(mali_jm_slot_template, mali_##name, \
TP_PROTO(int jobslot, u64 info_val), \
TP_ARGS(jobslot, info_val))
DEFINE_MALI_JM_SLOT_EVENT(JM_SUBMIT);
DEFINE_MALI_JM_SLOT_EVENT(JM_JOB_DONE);
DEFINE_MALI_JM_SLOT_EVENT(JM_UPDATE_HEAD);
DEFINE_MALI_JM_SLOT_EVENT(JM_CHECK_HEAD);
DEFINE_MALI_JM_SLOT_EVENT(JM_SOFTSTOP);
DEFINE_MALI_JM_SLOT_EVENT(JM_SOFTSTOP_0);
DEFINE_MALI_JM_SLOT_EVENT(JM_SOFTSTOP_1);
DEFINE_MALI_JM_SLOT_EVENT(JM_HARDSTOP);
DEFINE_MALI_JM_SLOT_EVENT(JM_HARDSTOP_0);
DEFINE_MALI_JM_SLOT_EVENT(JM_HARDSTOP_1);
DEFINE_MALI_JM_SLOT_EVENT(JM_SLOT_SOFT_OR_HARD_STOP);
DEFINE_MALI_JM_SLOT_EVENT(JM_SLOT_EVICT);
DEFINE_MALI_JM_SLOT_EVENT(JM_BEGIN_RESET_WORKER);
DEFINE_MALI_JM_SLOT_EVENT(JM_END_RESET_WORKER);
DEFINE_MALI_JM_SLOT_EVENT(JS_CORE_REF_REGISTER_ON_RECHECK_FAILED);
DEFINE_MALI_JM_SLOT_EVENT(JS_AFFINITY_SUBMIT_TO_BLOCKED);
DEFINE_MALI_JM_SLOT_EVENT(JS_AFFINITY_CURRENT);
DEFINE_MALI_JM_SLOT_EVENT(JD_DONE_TRY_RUN_NEXT_JOB);
DEFINE_MALI_JM_SLOT_EVENT(JS_CORE_REF_REQUEST_CORES_FAILED);
DEFINE_MALI_JM_SLOT_EVENT(JS_CORE_REF_REGISTER_INUSE_FAILED);
DEFINE_MALI_JM_SLOT_EVENT(JS_CORE_REF_REQUEST_ON_RECHECK_FAILED);
DEFINE_MALI_JM_SLOT_EVENT(JS_CORE_REF_AFFINITY_WOULD_VIOLATE);
DEFINE_MALI_JM_SLOT_EVENT(JS_JOB_DONE_TRY_RUN_NEXT_JOB);
DEFINE_MALI_JM_SLOT_EVENT(JS_JOB_DONE_RETRY_NEEDED);
DEFINE_MALI_JM_SLOT_EVENT(JS_POLICY_DEQUEUE_JOB);
DEFINE_MALI_JM_SLOT_EVENT(JS_POLICY_DEQUEUE_JOB_IRQ);
#undef DEFINE_MALI_JM_SLOT_EVENT
DECLARE_EVENT_CLASS(mali_jm_refcount_template,
TP_PROTO(int refcount, u64 info_val),
TP_ARGS(refcount, info_val),
TP_STRUCT__entry(
__field(unsigned int, refcount)
__field(u64, info_val)
),
TP_fast_assign(
__entry->refcount = refcount;
__entry->info_val = info_val;
),
TP_printk("refcount=%u info=0x%llx", __entry->refcount, __entry->info_val)
);
#define DEFINE_MALI_JM_REFCOUNT_EVENT(name) \
DEFINE_EVENT(mali_jm_refcount_template, mali_##name, \
TP_PROTO(int refcount, u64 info_val), \
TP_ARGS(refcount, info_val))
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_ADD_JOB);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_REMOVE_JOB);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_TRY_SCHEDULE_HEAD_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_INIT_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_TERM_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_ENQUEUE_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_DEQUEUE_HEAD_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_TRY_EVICT_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_RUNPOOL_ADD_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_RUNPOOL_REMOVE_CTX);
DEFINE_MALI_JM_REFCOUNT_EVENT(JS_POLICY_FOREACH_CTX_JOBS);
#undef DEFINE_MALI_JM_REFCOUNT_EVENT
DECLARE_EVENT_CLASS(mali_jm_add_template,
TP_PROTO(u64 gpu_addr, u64 info_val),
TP_ARGS(gpu_addr, info_val),
TP_STRUCT__entry(
__field(u64, gpu_addr)
__field(u64, info_val)
),
TP_fast_assign(
__entry->gpu_addr = gpu_addr;
__entry->info_val = info_val;
),
TP_printk("gpu_addr=0x%llx info=0x%llx", __entry->gpu_addr, __entry->info_val)
);
#define DEFINE_MALI_JM_ADD_EVENT(name) \
DEFINE_EVENT(mali_jm_add_template, mali_##name, \
TP_PROTO(u64 gpu_addr, u64 info_val), \
TP_ARGS(gpu_addr, info_val))
DEFINE_MALI_JM_ADD_EVENT(JD_DONE_WORKER);
DEFINE_MALI_JM_ADD_EVENT(JD_DONE_WORKER_END);
DEFINE_MALI_JM_ADD_EVENT(JD_CANCEL_WORKER);
DEFINE_MALI_JM_ADD_EVENT(JD_DONE);
DEFINE_MALI_JM_ADD_EVENT(JD_CANCEL);
DEFINE_MALI_JM_ADD_EVENT(JD_ZAP_CONTEXT);
DEFINE_MALI_JM_ADD_EVENT(JM_IRQ);
DEFINE_MALI_JM_ADD_EVENT(JM_IRQ_END);
DEFINE_MALI_JM_ADD_EVENT(JM_FLUSH_WORKQS);
DEFINE_MALI_JM_ADD_EVENT(JM_FLUSH_WORKQS_DONE);
DEFINE_MALI_JM_ADD_EVENT(JM_ZAP_NON_SCHEDULED);
DEFINE_MALI_JM_ADD_EVENT(JM_ZAP_SCHEDULED);
DEFINE_MALI_JM_ADD_EVENT(JM_ZAP_DONE);
DEFINE_MALI_JM_ADD_EVENT(JM_SUBMIT_AFTER_RESET);
DEFINE_MALI_JM_ADD_EVENT(JM_JOB_COMPLETE);
DEFINE_MALI_JM_ADD_EVENT(JS_CTX_ATTR_NOW_ON_RUNPOOL);
DEFINE_MALI_JM_ADD_EVENT(JS_CTX_ATTR_NOW_OFF_RUNPOOL);
DEFINE_MALI_JM_ADD_EVENT(JS_CTX_ATTR_NOW_ON_CTX);
DEFINE_MALI_JM_ADD_EVENT(JS_CTX_ATTR_NOW_OFF_CTX);
DEFINE_MALI_JM_ADD_EVENT(JS_POLICY_TIMER_END);
DEFINE_MALI_JM_ADD_EVENT(JS_POLICY_TIMER_START);
DEFINE_MALI_JM_ADD_EVENT(JS_POLICY_ENQUEUE_JOB);
#undef DEFINE_MALI_JM_ADD_EVENT
#endif /* !defined(_KBASE_DEBUG_LINUX_KTRACE_JM_H_) || defined(TRACE_HEADER_MULTI_READ)*/

View File

@ -0,0 +1,342 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <mali_kbase.h>
#include "debug/mali_kbase_debug_ktrace_internal.h"
int kbase_ktrace_init(struct kbase_device *kbdev)
{
#if KBASE_KTRACE_TARGET_RBUF
struct kbase_ktrace_msg *rbuf;
/* See also documentation of enum kbase_ktrace_code */
compiletime_assert(sizeof(kbase_ktrace_code_t) == sizeof(unsigned long long) ||
KBASE_KTRACE_CODE_COUNT <= (1ull << (sizeof(kbase_ktrace_code_t) * BITS_PER_BYTE)),
"kbase_ktrace_code_t not wide enough for KBASE_KTRACE_CODE_COUNT");
rbuf = kmalloc_array(KBASE_KTRACE_SIZE, sizeof(*rbuf), GFP_KERNEL);
if (!rbuf)
return -EINVAL;
kbdev->ktrace.rbuf = rbuf;
spin_lock_init(&kbdev->ktrace.lock);
#endif /* KBASE_KTRACE_TARGET_RBUF */
return 0;
}
void kbase_ktrace_term(struct kbase_device *kbdev)
{
#if KBASE_KTRACE_TARGET_RBUF
kfree(kbdev->ktrace.rbuf);
#endif /* KBASE_KTRACE_TARGET_RBUF */
}
void kbase_ktrace_hook_wrapper(void *param)
{
struct kbase_device *kbdev = (struct kbase_device *)param;
KBASE_KTRACE_DUMP(kbdev);
}
#if KBASE_KTRACE_TARGET_RBUF
static const char * const kbasep_ktrace_code_string[] = {
/*
* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
* THIS MUST BE USED AT THE START OF THE ARRAY
*/
#define KBASE_KTRACE_CODE_MAKE_CODE(X) # X
#include "debug/mali_kbase_debug_ktrace_codes.h"
#undef KBASE_KTRACE_CODE_MAKE_CODE
};
static void kbasep_ktrace_format_header(char *buffer, int sz, s32 written)
{
written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
"secs,thread_id,cpu,code,kctx,"), 0);
kbasep_ktrace_backend_format_header(buffer, sz, &written);
written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
",info_val,ktrace_version=%u.%u",
KBASE_KTRACE_VERSION_MAJOR,
KBASE_KTRACE_VERSION_MINOR), 0);
buffer[sz - 1] = 0;
}
static void kbasep_ktrace_format_msg(struct kbase_ktrace_msg *trace_msg,
char *buffer, int sz)
{
s32 written = 0;
/* Initial part of message:
*
* secs,thread_id,cpu,code,kctx,
*/
written += MAX(snprintf(buffer + written, MAX(sz - 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_ktrace_code_string[trace_msg->backend.code],
trace_msg->kctx), 0);
/* Backend parts */
kbasep_ktrace_backend_format_msg(trace_msg, buffer, sz,
&written);
/* Rest of message:
*
* ,info_val
*
* Note that the last column is empty, it's simply to hold the ktrace
* version in the header
*/
written += MAX(snprintf(buffer + written, MAX(sz - written, 0),
",0x%.16llx",
(unsigned long long)trace_msg->info_val), 0);
buffer[sz - 1] = 0;
}
static void kbasep_ktrace_dump_msg(struct kbase_device *kbdev,
struct kbase_ktrace_msg *trace_msg)
{
char buffer[KTRACE_DUMP_MESSAGE_SIZE];
lockdep_assert_held(&kbdev->ktrace.lock);
kbasep_ktrace_format_msg(trace_msg, buffer, sizeof(buffer));
dev_dbg(kbdev->dev, "%s", buffer);
}
struct kbase_ktrace_msg *kbasep_ktrace_reserve(struct kbase_ktrace *ktrace)
{
struct kbase_ktrace_msg *trace_msg;
lockdep_assert_held(&ktrace->lock);
trace_msg = &ktrace->rbuf[ktrace->next_in];
/* Update the ringbuffer indices */
ktrace->next_in = (ktrace->next_in + 1) & KBASE_KTRACE_MASK;
if (ktrace->next_in == ktrace->first_out)
ktrace->first_out = (ktrace->first_out + 1) & KBASE_KTRACE_MASK;
return trace_msg;
}
void kbasep_ktrace_msg_init(struct kbase_ktrace *ktrace,
struct kbase_ktrace_msg *trace_msg, enum kbase_ktrace_code code,
struct kbase_context *kctx, kbase_ktrace_flag_t flags,
u64 info_val)
{
lockdep_assert_held(&ktrace->lock);
trace_msg->thread_id = task_pid_nr(current);
trace_msg->cpu = task_cpu(current);
ktime_get_real_ts64(&trace_msg->timestamp);
trace_msg->kctx = kctx;
trace_msg->info_val = info_val;
trace_msg->backend.code = code;
trace_msg->backend.flags = flags;
}
void kbasep_ktrace_add(struct kbase_device *kbdev, enum kbase_ktrace_code code,
struct kbase_context *kctx, kbase_ktrace_flag_t flags,
u64 info_val)
{
unsigned long irqflags;
struct kbase_ktrace_msg *trace_msg;
spin_lock_irqsave(&kbdev->ktrace.lock, irqflags);
/* Reserve and update indices */
trace_msg = kbasep_ktrace_reserve(&kbdev->ktrace);
/* Fill the common part of the message (including backend.flags) */
kbasep_ktrace_msg_init(&kbdev->ktrace, trace_msg, code, kctx, flags,
info_val);
/* Done */
spin_unlock_irqrestore(&kbdev->ktrace.lock, irqflags);
}
static void kbasep_ktrace_clear_locked(struct kbase_device *kbdev)
{
lockdep_assert_held(&kbdev->ktrace.lock);
kbdev->ktrace.first_out = kbdev->ktrace.next_in;
}
void kbasep_ktrace_clear(struct kbase_device *kbdev)
{
unsigned long flags;
spin_lock_irqsave(&kbdev->ktrace.lock, flags);
kbasep_ktrace_clear_locked(kbdev);
spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
}
void kbasep_ktrace_dump(struct kbase_device *kbdev)
{
unsigned long flags;
u32 start;
u32 end;
char buffer[KTRACE_DUMP_MESSAGE_SIZE] = "Dumping trace:\n";
kbasep_ktrace_format_header(buffer, sizeof(buffer), strlen(buffer));
dev_dbg(kbdev->dev, "%s", buffer);
spin_lock_irqsave(&kbdev->ktrace.lock, flags);
start = kbdev->ktrace.first_out;
end = kbdev->ktrace.next_in;
while (start != end) {
struct kbase_ktrace_msg *trace_msg = &kbdev->ktrace.rbuf[start];
kbasep_ktrace_dump_msg(kbdev, trace_msg);
start = (start + 1) & KBASE_KTRACE_MASK;
}
dev_dbg(kbdev->dev, "TRACE_END");
kbasep_ktrace_clear_locked(kbdev);
spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
}
#ifdef CONFIG_DEBUG_FS
struct trace_seq_state {
struct kbase_ktrace_msg trace_buf[KBASE_KTRACE_SIZE];
u32 start;
u32 end;
};
static void *kbasep_ktrace_seq_start(struct seq_file *s, loff_t *pos)
{
struct trace_seq_state *state = s->private;
int i;
if (*pos == 0)
/* See Documentation/filesystems/seq_file.txt */
return SEQ_START_TOKEN;
if (*pos > KBASE_KTRACE_SIZE)
return NULL;
i = state->start + *pos;
if ((state->end >= state->start && i >= state->end) ||
i >= state->end + KBASE_KTRACE_SIZE)
return NULL;
i &= KBASE_KTRACE_MASK;
return &state->trace_buf[i];
}
static void kbasep_ktrace_seq_stop(struct seq_file *s, void *data)
{
}
static void *kbasep_ktrace_seq_next(struct seq_file *s, void *data, loff_t *pos)
{
struct trace_seq_state *state = s->private;
int i;
if (data != SEQ_START_TOKEN)
(*pos)++;
i = (state->start + *pos) & KBASE_KTRACE_MASK;
if (i == state->end)
return NULL;
return &state->trace_buf[i];
}
static int kbasep_ktrace_seq_show(struct seq_file *s, void *data)
{
struct kbase_ktrace_msg *trace_msg = data;
char buffer[KTRACE_DUMP_MESSAGE_SIZE];
/* If this is the start, print a header */
if (data == SEQ_START_TOKEN)
kbasep_ktrace_format_header(buffer, sizeof(buffer), 0);
else
kbasep_ktrace_format_msg(trace_msg, buffer, sizeof(buffer));
seq_printf(s, "%s\n", buffer);
return 0;
}
static const struct seq_operations kbasep_ktrace_seq_ops = {
.start = kbasep_ktrace_seq_start,
.next = kbasep_ktrace_seq_next,
.stop = kbasep_ktrace_seq_stop,
.show = kbasep_ktrace_seq_show,
};
static int kbasep_ktrace_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_ktrace_seq_ops,
sizeof(*state));
if (!state)
return -ENOMEM;
spin_lock_irqsave(&kbdev->ktrace.lock, flags);
state->start = kbdev->ktrace.first_out;
state->end = kbdev->ktrace.next_in;
memcpy(state->trace_buf, kbdev->ktrace.rbuf, sizeof(state->trace_buf));
spin_unlock_irqrestore(&kbdev->ktrace.lock, flags);
return 0;
}
static const struct file_operations kbasep_ktrace_debugfs_fops = {
.owner = THIS_MODULE,
.open = kbasep_ktrace_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
void kbase_ktrace_debugfs_init(struct kbase_device *kbdev)
{
debugfs_create_file("mali_trace", 0444,
kbdev->mali_debugfs_directory, kbdev,
&kbasep_ktrace_debugfs_fops);
}
#endif /* CONFIG_DEBUG_FS */
#else /* KBASE_KTRACE_TARGET_RBUF */
#ifdef CONFIG_DEBUG_FS
void kbase_ktrace_debugfs_init(struct kbase_device *kbdev)
{
CSTD_UNUSED(kbdev);
}
#endif /* CONFIG_DEBUG_FS */
#endif /* KBASE_KTRACE_TARGET_RBUF */

View File

@ -0,0 +1,219 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* DOC: Kbase's own trace, 'KTrace'
*
* Low overhead trace specific to kbase, aimed at:
* - common use-cases for tracing kbase specific functionality to do with
* running work on the GPU
* - easy 1-line addition of new types of trace
*
* KTrace can be recorded in one or more of the following targets:
* - KBASE_KTRACE_TARGET_RBUF: low overhead ringbuffer protected by an
* irq-spinlock, output available via dev_dbg() and debugfs file
* - KBASE_KTRACE_TARGET_FTRACE: ftrace based tracepoints under 'mali' events
*/
#ifndef _KBASE_DEBUG_KTRACE_H_
#define _KBASE_DEBUG_KTRACE_H_
#include "debug/backend/mali_kbase_debug_ktrace_jm.h"
/**
* kbase_ktrace_init - initialize kbase ktrace.
* @kbdev: kbase device
*/
int kbase_ktrace_init(struct kbase_device *kbdev);
/**
* kbase_ktrace_term - terminate kbase ktrace.
* @kbdev: kbase device
*/
void kbase_ktrace_term(struct kbase_device *kbdev);
/**
* kbase_ktrace_hook_wrapper - wrapper so that dumping ktrace can be done via a
* callback.
* @param: kbase device, cast to void pointer
*/
void kbase_ktrace_hook_wrapper(void *param);
#ifdef CONFIG_DEBUG_FS
/**
* kbase_ktrace_debugfs_init - initialize kbase ktrace for debugfs usage, if
* the selected targets support it.
* @kbdev: kbase device
*
* There is no matching 'term' call, debugfs_remove_recursive() is sufficient.
*/
void kbase_ktrace_debugfs_init(struct kbase_device *kbdev);
#endif /* CONFIG_DEBUG_FS */
/*
* KTrace target for internal ringbuffer
*/
#if KBASE_KTRACE_TARGET_RBUF
/**
* kbasep_ktrace_add - internal function to add trace to the ringbuffer.
* @kbdev: kbase device
* @code: ktrace code
* @kctx: kbase context, or NULL if no context
* @flags: flags about the message
* @info_val: generic information about @code to add to the trace
*
* PRIVATE: do not use directly. Use KBASE_KTRACE_ADD() instead.
*/
void kbasep_ktrace_add(struct kbase_device *kbdev, enum kbase_ktrace_code code,
struct kbase_context *kctx, kbase_ktrace_flag_t flags,
u64 info_val);
/**
* kbasep_ktrace_clear - clear the trace ringbuffer
* @kbdev: kbase device
*
* PRIVATE: do not use directly. Use KBASE_KTRACE_CLEAR() instead.
*/
void kbasep_ktrace_clear(struct kbase_device *kbdev);
/**
* kbasep_ktrace_dump - dump ktrace ringbuffer to dev_dbg(), then clear it
* @kbdev: kbase device
*
* PRIVATE: do not use directly. Use KBASE_KTRACE_DUMP() instead.
*/
void kbasep_ktrace_dump(struct kbase_device *kbdev);
#define KBASE_KTRACE_RBUF_ADD(kbdev, code, kctx, info_val) \
kbasep_ktrace_add(kbdev, KBASE_KTRACE_CODE(code), kctx, 0, \
info_val) \
#define KBASE_KTRACE_RBUF_CLEAR(kbdev) \
kbasep_ktrace_clear(kbdev)
#define KBASE_KTRACE_RBUF_DUMP(kbdev) \
kbasep_ktrace_dump(kbdev)
#else /* KBASE_KTRACE_TARGET_RBUF */
#define KBASE_KTRACE_RBUF_ADD(kbdev, code, kctx, info_val) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(code); \
CSTD_UNUSED(kctx); \
CSTD_UNUSED(info_val); \
CSTD_NOP(0); \
} while (0)
#define KBASE_KTRACE_RBUF_CLEAR(kbdev) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(0); \
} while (0)
#define KBASE_KTRACE_RBUF_DUMP(kbdev) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(0); \
} while (0)
#endif /* KBASE_KTRACE_TARGET_RBUF */
/*
* KTrace target for Linux's ftrace
*/
#if KBASE_KTRACE_TARGET_FTRACE
#include "mali_linux_trace.h"
#define KBASE_KTRACE_FTRACE_ADD(kbdev, code, kctx, info_val) \
trace_mali_##code(info_val)
#else /* KBASE_KTRACE_TARGET_FTRACE */
#define KBASE_KTRACE_FTRACE_ADD(kbdev, code, kctx, info_val) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(code); \
CSTD_UNUSED(kctx); \
CSTD_UNUSED(info_val); \
CSTD_NOP(0); \
} while (0)
#endif /* KBASE_KTRACE_TARGET_FTRACE */
/* No 'clear' implementation for ftrace yet */
#define KBASE_KTRACE_FTRACE_CLEAR(kbdev) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(0); \
} while (0)
/* No 'dump' implementation for ftrace yet */
#define KBASE_KTRACE_FTRACE_DUMP(kbdev) \
do { \
CSTD_UNUSED(kbdev); \
CSTD_NOP(0); \
} while (0)
/*
* Master set of macros to route KTrace to any of the targets
*/
/**
* KBASE_KTRACE_ADD - Add trace values
* @kbdev: kbase device
* @code: trace code
* @kctx: kbase context, or NULL if no context
* @info_val: generic information about @code to add to the trace
*
* Note: Any functions called through this macro will still be evaluated in
* Release builds (CONFIG_MALI_BIFROST_DEBUG not defined). Therefore, when
* KBASE_KTRACE_ENABLE == 0 any functions called to get the parameters supplied
* to this macro must:
* a) be static or static inline, and
* b) just return 0 and have no other statements present in the body.
*/
#define KBASE_KTRACE_ADD(kbdev, code, kctx, info_val) \
do { \
/* capture values that could come from non-pure function calls */ \
u64 __info_val = info_val; \
KBASE_KTRACE_RBUF_ADD(kbdev, code, kctx, __info_val); \
KBASE_KTRACE_FTRACE_ADD(kbdev, code, kctx, __info_val); \
} while (0)
/**
* KBASE_KTRACE_CLEAR - Clear the trace, if applicable to the target(s)
* @kbdev: kbase device
*/
#define KBASE_KTRACE_CLEAR(kbdev) \
do { \
KBASE_KTRACE_RBUF_CLEAR(kbdev); \
KBASE_KTRACE_FTRACE_CLEAR(kbdev); \
} while (0)
/**
* KBASE_KTRACE_DUMP - Dump the trace, if applicable to the target(s)
* @kbdev: kbase device
*/
#define KBASE_KTRACE_DUMP(kbdev) \
do { \
KBASE_KTRACE_RBUF_DUMP(kbdev); \
KBASE_KTRACE_FTRACE_DUMP(kbdev); \
} while (0)
#endif /* _KBASE_DEBUG_KTRACE_H_ */

View File

@ -0,0 +1,158 @@
/*
*
* (C) COPYRIGHT 2011-2015,2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* ***** IMPORTANT: THIS IS NOT A NORMAL HEADER FILE *****
* ***** DO NOT INCLUDE DIRECTLY *****
* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL *****
*/
/*
* The purpose of this header file is just to contain a list of trace code
* identifiers
*
* Each identifier is wrapped in a macro, so that its string form and enum form
* can be created
*
* Each macro is separated with a comma, to allow insertion into an array
* initializer or enum definition block.
*
* This allows automatic creation of an enum and a corresponding array of
* strings
*
* Before #including, the includer MUST #define KBASE_KTRACE_CODE_MAKE_CODE.
* After #including, the includer MUST #under KBASE_KTRACE_CODE_MAKE_CODE.
*
* e.g.:
* #define KBASE_KTRACE_CODE( X ) KBASE_KTRACE_CODE_ ## X
* typedef enum
* {
* #define KBASE_KTRACE_CODE_MAKE_CODE( X ) KBASE_KTRACE_CODE( X )
* #include "mali_kbase_debug_ktrace_codes.h"
* #undef KBASE_KTRACE_CODE_MAKE_CODE
* } kbase_ktrace_code;
*
* IMPORTANT: THIS FILE MUST NOT BE USED FOR ANY OTHER PURPOSE OTHER THAN THE ABOVE
*
*
* The use of the macro here is:
* - KBASE_KTRACE_CODE_MAKE_CODE( X )
*
* Which produces:
* - For an enum, KBASE_KTRACE_CODE_X
* - For a string, "X"
*
*
* For example:
* - KBASE_KTRACE_CODE_MAKE_CODE( JM_JOB_COMPLETE ) expands to:
* - KBASE_KTRACE_CODE_JM_JOB_COMPLETE for the enum
* - "JM_JOB_COMPLETE" for the string
* - To use it to trace an event, do:
* - KBASE_KTRACE_ADD( kbdev, JM_JOB_COMPLETE, subcode, kctx, uatom, val );
*/
#if 0 /* Dummy section to avoid breaking formatting */
int dummy_array[] = {
#endif
/*
* Core events
*/
/* no info_val */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_CTX_DESTROY),
/* no info_val */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_CTX_HWINSTR_TERM),
/* info_val == GPU_IRQ_STATUS register */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_IRQ),
/* info_val == bits cleared */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_IRQ_CLEAR),
/* info_val == GPU_IRQ_STATUS register */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_IRQ_DONE),
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_SOFT_RESET),
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_HARD_RESET),
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_PRFCNT_CLEAR),
/* info_val == dump address */
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_PRFCNT_SAMPLE),
KBASE_KTRACE_CODE_MAKE_CODE(CORE_GPU_CLEAN_INV_CACHES),
/*
* Power Management Events
*/
KBASE_KTRACE_CODE_MAKE_CODE(PM_JOB_SUBMIT_AFTER_POWERING_UP),
KBASE_KTRACE_CODE_MAKE_CODE(PM_JOB_SUBMIT_AFTER_POWERED_UP),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWRON),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWRON_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWRON_L2),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWROFF),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWROFF_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_PWROFF_L2),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_POWERED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_POWERED_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_POWERED_L2),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_DESIRED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_DESIRED_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_AVAILABLE),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_CHANGE_AVAILABLE_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_AVAILABLE),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CORES_AVAILABLE_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_DESIRED_REACHED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_DESIRED_REACHED_TILER),
KBASE_KTRACE_CODE_MAKE_CODE(PM_RELEASE_CHANGE_SHADER_NEEDED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_RELEASE_CHANGE_TILER_NEEDED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_REQUEST_CHANGE_SHADER_NEEDED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_REQUEST_CHANGE_TILER_NEEDED),
KBASE_KTRACE_CODE_MAKE_CODE(PM_WAKE_WAITERS),
/* info_val == kbdev->pm.active_count*/
KBASE_KTRACE_CODE_MAKE_CODE(PM_CONTEXT_ACTIVE),
/* info_val == kbdev->pm.active_count*/
KBASE_KTRACE_CODE_MAKE_CODE(PM_CONTEXT_IDLE),
KBASE_KTRACE_CODE_MAKE_CODE(PM_GPU_ON),
KBASE_KTRACE_CODE_MAKE_CODE(PM_GPU_OFF),
/* info_val == policy number, or -1 for "Already changing" */
KBASE_KTRACE_CODE_MAKE_CODE(PM_SET_POLICY),
KBASE_KTRACE_CODE_MAKE_CODE(PM_CA_SET_POLICY),
/* info_val == policy number */
KBASE_KTRACE_CODE_MAKE_CODE(PM_CURRENT_POLICY_INIT),
/* info_val == policy number */
KBASE_KTRACE_CODE_MAKE_CODE(PM_CURRENT_POLICY_TERM),
/*
* Context Scheduler events
*/
/* info_val == kctx->refcount */
KBASE_KTRACE_CODE_MAKE_CODE(SCHED_RETAIN_CTX_NOLOCK),
/* info_val == kctx->refcount */
KBASE_KTRACE_CODE_MAKE_CODE(SCHED_RELEASE_CTX),
#include "debug/backend/mali_kbase_debug_ktrace_codes_jm.h"
/*
* Unused code just to make it easier to not have a comma at the end.
* All other codes MUST come before this
*/
KBASE_KTRACE_CODE_MAKE_CODE(DUMMY)
#if 0 /* Dummy section to avoid breaking formatting */
};
#endif
/* ***** THE LACK OF HEADER GUARDS IS INTENTIONAL ***** */

View File

@ -0,0 +1,152 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_DEBUG_KTRACE_DEFS_H_
#define _KBASE_DEBUG_KTRACE_DEFS_H_
/* Enable SW tracing when set */
#if defined(CONFIG_MALI_BIFROST_ENABLE_TRACE) || defined(CONFIG_MALI_BIFROST_SYSTEM_TRACE)
#define KBASE_KTRACE_ENABLE 1
#endif
#ifndef KBASE_KTRACE_ENABLE
#ifdef CONFIG_MALI_BIFROST_DEBUG
#define KBASE_KTRACE_ENABLE 1
#else /* CONFIG_MALI_BIFROST_DEBUG */
#define KBASE_KTRACE_ENABLE 0
#endif /* CONFIG_MALI_BIFROST_DEBUG */
#endif /* KBASE_KTRACE_ENABLE */
/* Select targets for recording of trace:
*
*/
#if KBASE_KTRACE_ENABLE
#ifdef CONFIG_MALI_BIFROST_SYSTEM_TRACE
#define KBASE_KTRACE_TARGET_FTRACE 1
#else /* CONFIG_MALI_BIFROST_SYSTEM_TRACE */
#define KBASE_KTRACE_TARGET_FTRACE 0
#endif /* CONFIG_MALI_BIFROST_SYSTEM_TRACE */
#ifdef CONFIG_MALI_BIFROST_ENABLE_TRACE
#define KBASE_KTRACE_TARGET_RBUF 1
#else /* CONFIG_MALI_BIFROST_ENABLE_TRACE*/
#define KBASE_KTRACE_TARGET_RBUF 0
#endif /* CONFIG_MALI_BIFROST_ENABLE_TRACE */
#else /* KBASE_KTRACE_ENABLE */
#define KBASE_KTRACE_TARGET_FTRACE 0
#define KBASE_KTRACE_TARGET_RBUF 0
#endif /* KBASE_KTRACE_ENABLE */
/*
* NOTE: KBASE_KTRACE_VERSION_MAJOR, KBASE_KTRACE_VERSION_MINOR are kept in
* the backend, since updates can be made to one backend in a way that doesn't
* affect the other.
*
* However, modifying the common part could require both backend versions to be
* updated.
*/
#if KBASE_KTRACE_TARGET_RBUF
typedef u8 kbase_ktrace_flag_t;
typedef u8 kbase_ktrace_code_t;
/*
* struct kbase_ktrace_backend - backend specific part of a trace message
*
* At the very least, this must contain a kbase_ktrace_code_t 'code' member and
* a kbase_ktrace_flag_t 'flags' member
*/
struct kbase_ktrace_backend;
#include "debug/backend/mali_kbase_debug_ktrace_defs_jm.h"
/* Indicates if the trace message has backend related info.
*
* If not set, consider the &kbase_ktrace_backend part of a &kbase_ktrace_msg
* as uninitialized, apart from the mandatory parts:
* - code
* - flags
*/
#define KBASE_KTRACE_FLAG_BACKEND (((kbase_ktrace_flag_t)1) << 7)
#define KBASE_KTRACE_SHIFT 8 /* 256 entries */
#define KBASE_KTRACE_SIZE (1 << KBASE_KTRACE_SHIFT)
#define KBASE_KTRACE_MASK ((1 << KBASE_KTRACE_SHIFT)-1)
#define KBASE_KTRACE_CODE(X) KBASE_KTRACE_CODE_ ## X
/* Note: compiletime_assert() about this against kbase_ktrace_code_t is in
* kbase_ktrace_init()
*/
enum kbase_ktrace_code {
/*
* IMPORTANT: USE OF SPECIAL #INCLUDE OF NON-STANDARD HEADER FILE
* THIS MUST BE USED AT THE START OF THE ENUM
*/
#define KBASE_KTRACE_CODE_MAKE_CODE(X) KBASE_KTRACE_CODE(X)
#include <debug/mali_kbase_debug_ktrace_codes.h>
#undef KBASE_KTRACE_CODE_MAKE_CODE
/* Comma on its own, to extend the list */
,
/* Must be the last in the enum */
KBASE_KTRACE_CODE_COUNT
};
/**
* struct kbase_ktrace - object representing a trace message added to trace
* buffer trace_rbuf in &kbase_device
* @timestamp: CPU timestamp at which the trace message was added.
* @thread_id: id of the thread in the context of which trace message was
* added.
* @cpu: indicates which CPU the @thread_id was scheduled on when the
* trace message was added.
* @kctx: Pointer to the kbase context for which the trace message was
* added. Will be NULL for certain trace messages associated with
* the &kbase_device itself, such as power management events.
* Will point to the appropriate context corresponding to
* backend-specific events.
* @info_val: value specific to the type of event being traced. Refer to the
* specific code in enum kbase_ktrace_code
* @backend: backend-specific trace information. All backends must implement
* a minimum common set of members
*/
struct kbase_ktrace_msg {
struct timespec64 timestamp;
u32 thread_id;
u32 cpu;
void *kctx;
u64 info_val;
struct kbase_ktrace_backend backend;
};
struct kbase_ktrace {
spinlock_t lock;
u16 first_out;
u16 next_in;
struct kbase_ktrace_msg *rbuf;
};
#endif /* KBASE_KTRACE_TARGET_RBUF */
#endif /* _KBASE_DEBUG_KTRACE_DEFS_H_ */

View File

@ -0,0 +1,89 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_DEBUG_KTRACE_INTERNAL_H_
#define _KBASE_DEBUG_KTRACE_INTERNAL_H_
#if KBASE_KTRACE_TARGET_RBUF
#define KTRACE_DUMP_MESSAGE_SIZE 256
/**
* kbasep_ktrace_backend_format_header - format the backend part of the header
* @buffer: buffer to write to
* @sz: size of @buffer in bytes
* @written: pointer to storage for updating bytes written so far to @buffer
*
* The backend must format only the non-common backend specific parts of the
* header. It must format them as though they were standalone. The caller will
* handle adding any delimiters around this.
*/
void kbasep_ktrace_backend_format_header(char *buffer, int sz, s32 *written);
/**
* kbasep_ktrace_backend_format_msg - format the backend part of the message
* @trace_msg: ktrace message
* @buffer: buffer to write to
* @sz: size of @buffer in bytes
* @written: pointer to storage for updating bytes written so far to @buffer
*
* The backend must format only the non-common backend specific parts of the
* message. It must format them as though they were standalone. The caller will
* handle adding any delimiters around this.
*
* A caller may have the flags member of @trace_msg with
* %KBASE_KTRACE_FLAG_BACKEND clear. The backend must handle that setting
* appropriately.
*/
void kbasep_ktrace_backend_format_msg(struct kbase_ktrace_msg *trace_msg,
char *buffer, int sz, s32 *written);
/**
* kbasep_ktrace_reserve - internal function to reserve space for a ktrace
* message
* @ktrace: kbase device's ktrace
*
* This may also empty the oldest entry in the ringbuffer to make space.
*/
struct kbase_ktrace_msg *kbasep_ktrace_reserve(struct kbase_ktrace *ktrace);
/**
* kbasep_ktrace_msg_init - internal function to initialize just the common
* part of a ktrace message
* @ktrace: kbase device's ktrace
* @trace_msg: ktrace message to initialize
* @code: ktrace code
* @kctx: kbase context, or NULL if no context
* @flags: flags about the message
* @info_val: generic information about @code to add to the trace
*
* The common part includes the mandatory parts of the backend part
*/
void kbasep_ktrace_msg_init(struct kbase_ktrace *ktrace,
struct kbase_ktrace_msg *trace_msg, enum kbase_ktrace_code code,
struct kbase_context *kctx, kbase_ktrace_flag_t flags,
u64 info_val);
#endif /* KBASE_KTRACE_TARGET_RBUF */
#endif /* _KBASE_DEBUG_KTRACE_INTERNAL_H_ */

View File

@ -0,0 +1,99 @@
/*
*
* (C) COPYRIGHT 2014,2018,2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* NOTE: This must **only** be included through mali_linux_trace.h,
* otherwise it will fail to setup tracepoints correctly
*/
#if !defined(_KBASE_DEBUG_LINUX_KTRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _KBASE_DEBUG_LINUX_KTRACE_H_
#if KBASE_KTRACE_TARGET_FTRACE
DECLARE_EVENT_CLASS(mali_add_template,
TP_PROTO(u64 info_val),
TP_ARGS(info_val),
TP_STRUCT__entry(
__field(u64, info_val)
),
TP_fast_assign(
__entry->info_val = info_val;
),
TP_printk("info=0x%llx", __entry->info_val)
);
#define DEFINE_MALI_ADD_EVENT(name) \
DEFINE_EVENT(mali_add_template, mali_##name, \
TP_PROTO(u64 info_val), \
TP_ARGS(info_val))
DEFINE_MALI_ADD_EVENT(CORE_CTX_DESTROY);
DEFINE_MALI_ADD_EVENT(CORE_CTX_HWINSTR_TERM);
DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ);
DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ_CLEAR);
DEFINE_MALI_ADD_EVENT(CORE_GPU_IRQ_DONE);
DEFINE_MALI_ADD_EVENT(CORE_GPU_SOFT_RESET);
DEFINE_MALI_ADD_EVENT(CORE_GPU_HARD_RESET);
DEFINE_MALI_ADD_EVENT(CORE_GPU_PRFCNT_SAMPLE);
DEFINE_MALI_ADD_EVENT(CORE_GPU_PRFCNT_CLEAR);
DEFINE_MALI_ADD_EVENT(CORE_GPU_CLEAN_INV_CACHES);
DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_DESIRED);
DEFINE_MALI_ADD_EVENT(PM_JOB_SUBMIT_AFTER_POWERING_UP);
DEFINE_MALI_ADD_EVENT(PM_JOB_SUBMIT_AFTER_POWERED_UP);
DEFINE_MALI_ADD_EVENT(PM_PWRON);
DEFINE_MALI_ADD_EVENT(PM_PWRON_TILER);
DEFINE_MALI_ADD_EVENT(PM_PWRON_L2);
DEFINE_MALI_ADD_EVENT(PM_PWROFF);
DEFINE_MALI_ADD_EVENT(PM_PWROFF_TILER);
DEFINE_MALI_ADD_EVENT(PM_PWROFF_L2);
DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED);
DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED_TILER);
DEFINE_MALI_ADD_EVENT(PM_CORES_POWERED_L2);
DEFINE_MALI_ADD_EVENT(PM_DESIRED_REACHED);
DEFINE_MALI_ADD_EVENT(PM_DESIRED_REACHED_TILER);
DEFINE_MALI_ADD_EVENT(PM_REQUEST_CHANGE_SHADER_NEEDED);
DEFINE_MALI_ADD_EVENT(PM_REQUEST_CHANGE_TILER_NEEDED);
DEFINE_MALI_ADD_EVENT(PM_RELEASE_CHANGE_SHADER_NEEDED);
DEFINE_MALI_ADD_EVENT(PM_RELEASE_CHANGE_TILER_NEEDED);
DEFINE_MALI_ADD_EVENT(PM_CORES_AVAILABLE);
DEFINE_MALI_ADD_EVENT(PM_CORES_AVAILABLE_TILER);
DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_AVAILABLE);
DEFINE_MALI_ADD_EVENT(PM_CORES_CHANGE_AVAILABLE_TILER);
DEFINE_MALI_ADD_EVENT(PM_GPU_ON);
DEFINE_MALI_ADD_EVENT(PM_GPU_OFF);
DEFINE_MALI_ADD_EVENT(PM_SET_POLICY);
DEFINE_MALI_ADD_EVENT(PM_CURRENT_POLICY_INIT);
DEFINE_MALI_ADD_EVENT(PM_CURRENT_POLICY_TERM);
DEFINE_MALI_ADD_EVENT(PM_CA_SET_POLICY);
DEFINE_MALI_ADD_EVENT(PM_CONTEXT_ACTIVE);
DEFINE_MALI_ADD_EVENT(PM_CONTEXT_IDLE);
DEFINE_MALI_ADD_EVENT(PM_WAKE_WAITERS);
DEFINE_MALI_ADD_EVENT(SCHED_RETAIN_CTX_NOLOCK);
DEFINE_MALI_ADD_EVENT(SCHED_RELEASE_CTX);
#undef DEFINE_MALI_ADD_EVENT
#include "mali_kbase_debug_linux_ktrace_jm.h"
#endif /* KBASE_KTRACE_TARGET_FTRACE */
#endif /* !defined(_KBASE_DEBUG_LINUX_KTRACE_H_) || defined(TRACE_HEADER_MULTI_READ) */

View File

@ -0,0 +1,260 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include "../mali_kbase_device_internal.h"
#include "../mali_kbase_device.h"
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_hwaccess_backend.h>
#include <mali_kbase_ctx_sched.h>
#include <mali_kbase_reset_gpu.h>
#ifdef CONFIG_MALI_BIFROST_NO_MALI
#include <mali_kbase_model_linux.h>
#endif
#ifdef CONFIG_MALI_ARBITER_SUPPORT
#include <arbiter/mali_kbase_arbiter_pm.h>
#endif
#include <mali_kbase.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>
#include <mali_kbase_dummy_job_wa.h>
/**
* kbase_backend_late_init - Perform any backend-specific initialization.
* @kbdev: Device pointer
*
* Return: 0 on success, or an error code on failure.
*/
static int kbase_backend_late_init(struct kbase_device *kbdev)
{
int err;
err = kbase_hwaccess_pm_init(kbdev);
if (err)
return err;
err = kbase_reset_gpu_init(kbdev);
if (err)
goto fail_reset_gpu_init;
err = kbase_hwaccess_pm_powerup(kbdev, PM_HW_ISSUES_DETECT);
if (err)
goto fail_pm_powerup;
err = kbase_backend_timer_init(kbdev);
if (err)
goto fail_timer;
#ifdef CONFIG_MALI_BIFROST_DEBUG
#ifndef CONFIG_MALI_BIFROST_NO_MALI
if (kbasep_common_test_interrupt_handlers(kbdev) != 0) {
dev_err(kbdev->dev, "Interrupt assignment check failed.\n");
err = -EINVAL;
goto fail_interrupt_test;
}
#endif /* !CONFIG_MALI_BIFROST_NO_MALI */
#endif /* CONFIG_MALI_BIFROST_DEBUG */
err = kbase_job_slot_init(kbdev);
if (err)
goto fail_job_slot;
/* Do the initialisation of devfreq.
* Devfreq needs backend_timer_init() for completion of its
* initialisation and it also needs to catch the first callback
* occurrence of the runtime_suspend event for maintaining state
* coherence with the backend power management, hence needs to be
* placed before the kbase_pm_context_idle().
*/
err = kbase_backend_devfreq_init(kbdev);
if (err)
goto fail_devfreq_init;
/* Idle the GPU and/or cores, if the policy wants it to */
kbase_pm_context_idle(kbdev);
/* Update gpuprops with L2_FEATURES if applicable */
err = kbase_gpuprops_update_l2_features(kbdev);
if (err)
goto fail_update_l2_features;
init_waitqueue_head(&kbdev->hwaccess.backend.reset_wait);
return 0;
fail_update_l2_features:
fail_devfreq_init:
kbase_job_slot_term(kbdev);
fail_job_slot:
#ifdef CONFIG_MALI_BIFROST_DEBUG
#ifndef CONFIG_MALI_BIFROST_NO_MALI
fail_interrupt_test:
#endif /* !CONFIG_MALI_BIFROST_NO_MALI */
#endif /* CONFIG_MALI_BIFROST_DEBUG */
kbase_backend_timer_term(kbdev);
fail_timer:
kbase_hwaccess_pm_halt(kbdev);
fail_pm_powerup:
kbase_reset_gpu_term(kbdev);
fail_reset_gpu_init:
kbase_hwaccess_pm_term(kbdev);
return err;
}
/**
* kbase_backend_late_term - Perform any backend-specific termination.
* @kbdev: Device pointer
*/
static void kbase_backend_late_term(struct kbase_device *kbdev)
{
kbase_backend_devfreq_term(kbdev);
kbase_job_slot_halt(kbdev);
kbase_job_slot_term(kbdev);
kbase_backend_timer_term(kbdev);
kbase_hwaccess_pm_halt(kbdev);
kbase_reset_gpu_term(kbdev);
kbase_hwaccess_pm_term(kbdev);
}
static const struct kbase_device_init dev_init[] = {
#ifdef CONFIG_MALI_BIFROST_NO_MALI
{kbase_gpu_device_create, kbase_gpu_device_destroy,
"Dummy model initialization failed"},
#else
{assign_irqs, NULL,
"IRQ search failed"},
{registers_map, registers_unmap,
"Register map failed"},
#endif
{kbase_device_io_history_init, kbase_device_io_history_term,
"Register access history initialization failed"},
{kbase_device_pm_init, kbase_device_pm_term,
"Power management initialization failed"},
{kbase_device_early_init, kbase_device_early_term,
"Early device initialization failed"},
{kbase_device_populate_max_freq, NULL,
"Populating max frequency failed"},
{kbase_device_misc_init, kbase_device_misc_term,
"Miscellaneous device initialization failed"},
{kbase_ctx_sched_init, kbase_ctx_sched_term,
"Context scheduler initialization failed"},
{kbase_mem_init, kbase_mem_term,
"Memory subsystem initialization failed"},
{kbase_device_coherency_init, NULL,
"Device coherency init failed"},
{kbase_protected_mode_init, kbase_protected_mode_term,
"Protected mode subsystem initialization failed"},
{kbase_device_list_init, kbase_device_list_term,
"Device list setup failed"},
{kbasep_js_devdata_init, kbasep_js_devdata_term,
"Job JS devdata initialization failed"},
{kbase_device_timeline_init, kbase_device_timeline_term,
"Timeline stream initialization failed"},
{kbase_device_hwcnt_backend_gpu_init,
kbase_device_hwcnt_backend_gpu_term,
"GPU hwcnt backend creation failed"},
{kbase_device_hwcnt_context_init, kbase_device_hwcnt_context_term,
"GPU hwcnt context initialization failed"},
{kbase_device_hwcnt_virtualizer_init,
kbase_device_hwcnt_virtualizer_term,
"GPU hwcnt virtualizer initialization failed"},
{kbase_device_vinstr_init, kbase_device_vinstr_term,
"Virtual instrumentation initialization failed"},
{kbase_backend_late_init, kbase_backend_late_term,
"Late backend initialization failed"},
#ifdef MALI_KBASE_BUILD
{kbase_debug_job_fault_dev_init, kbase_debug_job_fault_dev_term,
"Job fault debug initialization failed"},
{kbase_device_debugfs_init, kbase_device_debugfs_term,
"DebugFS initialization failed"},
/* Sysfs init needs to happen before registering the device with
* misc_register(), otherwise it causes a race condition between
* registering the device and a uevent event being generated for
* userspace, causing udev rules to run which might expect certain
* sysfs attributes present. As a result of the race condition
* we avoid, some Mali sysfs entries may have appeared to udev
* to not exist.
* For more information, see
* https://www.kernel.org/doc/Documentation/driver-model/device.txt, the
* paragraph that starts with "Word of warning", currently the
* second-last paragraph.
*/
{kbase_sysfs_init, kbase_sysfs_term, "SysFS group creation failed"},
{kbase_device_misc_register, kbase_device_misc_deregister,
"Misc device registration failed"},
#ifdef CONFIG_MALI_BUSLOG
{buslog_init, buslog_term, "Bus log client registration failed"},
#endif
{kbase_gpuprops_populate_user_buffer, kbase_gpuprops_free_user_buffer,
"GPU property population failed"},
#endif
{kbase_dummy_job_wa_load, kbase_dummy_job_wa_cleanup,
"Dummy job workaround load failed"},
};
static void kbase_device_term_partial(struct kbase_device *kbdev,
unsigned int i)
{
while (i-- > 0) {
if (dev_init[i].term)
dev_init[i].term(kbdev);
}
}
void kbase_device_term(struct kbase_device *kbdev)
{
kbase_device_term_partial(kbdev, ARRAY_SIZE(dev_init));
kbasep_js_devdata_halt(kbdev);
kbase_mem_halt(kbdev);
}
int kbase_device_init(struct kbase_device *kbdev)
{
int err = 0;
unsigned int i = 0;
dev_info(kbdev->dev, "Kernel DDK version %s", MALI_RELEASE_NAME);
kbase_device_id_init(kbdev);
kbase_disjoint_init(kbdev);
for (i = 0; i < ARRAY_SIZE(dev_init); i++) {
err = dev_init[i].init(kbdev);
if (err) {
dev_err(kbdev->dev, "%s error = %d\n",
dev_init[i].err_mes, err);
kbase_device_term_partial(kbdev, i);
break;
}
}
return err;
}

View File

@ -0,0 +1,429 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* 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 <linux/types.h>
#include <mali_kbase.h>
#include <mali_kbase_defs.h>
#include <mali_kbase_hwaccess_instr.h>
#include <mali_kbase_hw.h>
#include <mali_kbase_config_defaults.h>
#include <tl/mali_kbase_timeline.h>
#include "mali_kbase_vinstr.h"
#include "mali_kbase_hwcnt_context.h"
#include "mali_kbase_hwcnt_virtualizer.h"
#include "mali_kbase_device.h"
#include "mali_kbase_device_internal.h"
#include "backend/gpu/mali_kbase_pm_internal.h"
#include "backend/gpu/mali_kbase_irq_internal.h"
#ifdef CONFIG_MALI_ARBITER_SUPPORT
#include "arbiter/mali_kbase_arbiter_pm.h"
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
/* 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
/* Number of register accesses for the buffer that we allocate during
* initialization time. The buffer size can be changed later via debugfs.
*/
#define KBASEP_DEFAULT_REGISTER_HISTORY_SIZE ((u16)512)
static DEFINE_MUTEX(kbase_dev_list_lock);
static LIST_HEAD(kbase_dev_list);
static int kbase_dev_nr;
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)
{
kbdev->as[i].number = i;
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", 0, 1, i);
if (!kbdev->as[i].pf_wq)
return -EINVAL;
INIT_WORK(&kbdev->as[i].work_pagefault, page_fault_worker);
INIT_WORK(&kbdev->as[i].work_busfault, bus_fault_worker);
return 0;
}
static void kbase_device_as_term(struct kbase_device *kbdev, int i)
{
destroy_workqueue(kbdev->as[i].pf_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_misc_init(struct kbase_device * const kbdev)
{
int err;
#ifdef CONFIG_ARM64
struct device_node *np = NULL;
#endif /* CONFIG_ARM64 */
spin_lock_init(&kbdev->mmu_mask_change);
mutex_init(&kbdev->mmu_hw_mutex);
#ifdef CONFIG_ARM64
kbdev->cci_snoop_enabled = false;
np = kbdev->dev->of_node;
if (np != NULL) {
if (of_property_read_u32(np, "snoop_enable_smc",
&kbdev->snoop_enable_smc))
kbdev->snoop_enable_smc = 0;
if (of_property_read_u32(np, "snoop_disable_smc",
&kbdev->snoop_disable_smc))
kbdev->snoop_disable_smc = 0;
/* Either both or none of the calls should be provided. */
if (!((kbdev->snoop_disable_smc == 0
&& kbdev->snoop_enable_smc == 0)
|| (kbdev->snoop_disable_smc != 0
&& kbdev->snoop_enable_smc != 0))) {
WARN_ON(1);
err = -EINVAL;
goto fail;
}
}
#endif /* CONFIG_ARM64 */
/* 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);
err = kbase_gpuprops_set_features(kbdev);
if (err)
goto fail;
/* 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 = kbase_ktrace_init(kbdev);
if (err)
goto term_as;
init_waitqueue_head(&kbdev->cache_clean_wait);
kbase_debug_assert_register_hook(&kbase_ktrace_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;
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU))
kbdev->mmu_mode = kbase_mmu_mode_get_aarch64();
else
kbdev->mmu_mode = kbase_mmu_mode_get_lpae();
mutex_init(&kbdev->kctx_list_lock);
INIT_LIST_HEAD(&kbdev->kctx_list);
spin_lock_init(&kbdev->hwaccess_lock);
return 0;
term_trace:
kbase_ktrace_term(kbdev);
term_as:
kbase_device_all_as_term(kbdev);
as_init_failed:
dma_set_mask_failed:
fail:
return err;
}
void kbase_device_misc_term(struct kbase_device *kbdev)
{
KBASE_DEBUG_ASSERT(kbdev);
WARN_ON(!list_empty(&kbdev->kctx_list));
#if KBASE_KTRACE_ENABLE
kbase_debug_assert_register_hook(NULL, NULL);
#endif
kbase_instr_backend_term(kbdev);
kbase_ktrace_term(kbdev);
kbase_device_all_as_term(kbdev);
}
void kbase_device_free(struct kbase_device *kbdev)
{
kfree(kbdev);
}
void kbase_device_id_init(struct kbase_device *kbdev)
{
scnprintf(kbdev->devname, DEVNAME_SIZE, "%s%d", kbase_drv_name,
kbase_dev_nr);
kbdev->id = kbase_dev_nr;
}
void kbase_increment_device_id(void)
{
kbase_dev_nr++;
}
int kbase_device_hwcnt_backend_gpu_init(struct kbase_device *kbdev)
{
return kbase_hwcnt_backend_gpu_create(kbdev, &kbdev->hwcnt_gpu_iface);
}
void kbase_device_hwcnt_backend_gpu_term(struct kbase_device *kbdev)
{
kbase_hwcnt_backend_gpu_destroy(&kbdev->hwcnt_gpu_iface);
}
int kbase_device_hwcnt_context_init(struct kbase_device *kbdev)
{
return kbase_hwcnt_context_init(&kbdev->hwcnt_gpu_iface,
&kbdev->hwcnt_gpu_ctx);
}
void kbase_device_hwcnt_context_term(struct kbase_device *kbdev)
{
kbase_hwcnt_context_term(kbdev->hwcnt_gpu_ctx);
}
int kbase_device_hwcnt_virtualizer_init(struct kbase_device *kbdev)
{
return kbase_hwcnt_virtualizer_init(kbdev->hwcnt_gpu_ctx,
KBASE_HWCNT_GPU_VIRTUALIZER_DUMP_THRESHOLD_NS,
&kbdev->hwcnt_gpu_virt);
}
void kbase_device_hwcnt_virtualizer_term(struct kbase_device *kbdev)
{
kbase_hwcnt_virtualizer_term(kbdev->hwcnt_gpu_virt);
}
int kbase_device_timeline_init(struct kbase_device *kbdev)
{
atomic_set(&kbdev->timeline_flags, 0);
return kbase_timeline_init(&kbdev->timeline, &kbdev->timeline_flags);
}
void kbase_device_timeline_term(struct kbase_device *kbdev)
{
kbase_timeline_term(kbdev->timeline);
}
int kbase_device_vinstr_init(struct kbase_device *kbdev)
{
return kbase_vinstr_init(kbdev->hwcnt_gpu_virt, &kbdev->vinstr_ctx);
}
void kbase_device_vinstr_term(struct kbase_device *kbdev)
{
kbase_vinstr_term(kbdev->vinstr_ctx);
}
int kbase_device_io_history_init(struct kbase_device *kbdev)
{
return kbase_io_history_init(&kbdev->io_history,
KBASEP_DEFAULT_REGISTER_HISTORY_SIZE);
}
void kbase_device_io_history_term(struct kbase_device *kbdev)
{
kbase_io_history_term(&kbdev->io_history);
}
int kbase_device_misc_register(struct kbase_device *kbdev)
{
return misc_register(&kbdev->mdev);
}
void kbase_device_misc_deregister(struct kbase_device *kbdev)
{
misc_deregister(&kbdev->mdev);
}
int kbase_device_list_init(struct kbase_device *kbdev)
{
const struct list_head *dev_list;
dev_list = kbase_device_get_list();
list_add(&kbdev->entry, &kbase_dev_list);
kbase_device_put_list(dev_list);
return 0;
}
void kbase_device_list_term(struct kbase_device *kbdev)
{
const struct list_head *dev_list;
dev_list = kbase_device_get_list();
list_del(&kbdev->entry);
kbase_device_put_list(dev_list);
}
const struct list_head *kbase_device_get_list(void)
{
mutex_lock(&kbase_dev_list_lock);
return &kbase_dev_list;
}
KBASE_EXPORT_TEST_API(kbase_device_get_list);
void kbase_device_put_list(const struct list_head *dev_list)
{
mutex_unlock(&kbase_dev_list_lock);
}
KBASE_EXPORT_TEST_API(kbase_device_put_list);
int kbase_device_early_init(struct kbase_device *kbdev)
{
int err;
err = kbasep_platform_device_init(kbdev);
if (err)
return err;
err = kbase_pm_runtime_init(kbdev);
if (err)
goto fail_runtime_pm;
/* 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_install_interrupts(kbdev);
if (err)
goto fail_interrupts;
return 0;
fail_interrupts:
kbase_pm_runtime_term(kbdev);
fail_runtime_pm:
kbasep_platform_device_term(kbdev);
return err;
}
void kbase_device_early_term(struct kbase_device *kbdev)
{
#ifdef CONFIG_MALI_ARBITER_SUPPORT
if (kbdev->arb.arb_if)
kbase_arbiter_pm_release_interrupts(kbdev);
else
kbase_release_interrupts(kbdev);
#else
kbase_release_interrupts(kbdev);
#endif /* CONFIG_MALI_ARBITER_SUPPORT */
kbase_pm_runtime_term(kbdev);
kbasep_platform_device_term(kbdev);
}

View File

@ -0,0 +1,71 @@
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <mali_kbase.h>
/**
* kbase_device_get_list - get device list.
*
* Get access to device list.
*
* Return: Pointer to the linked list head.
*/
const struct list_head *kbase_device_get_list(void);
/**
* kbase_device_put_list - put device list.
*
* @dev_list: head of linked list containing device list.
*
* Put access to the device list.
*/
void kbase_device_put_list(const struct list_head *dev_list);
/**
* Kbase_increment_device_id - increment device id.
*
* Used to increment device id on successful initialization of the device.
*/
void kbase_increment_device_id(void);
/**
* kbase_device_init - Device initialisation.
*
* This is called from device probe to initialise various other
* components needed.
*
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Return: 0 on success and non-zero value on failure.
*/
int kbase_device_init(struct kbase_device *kbdev);
/**
* kbase_device_term - Device termination.
*
* This is called from device remove to terminate various components that
* were initialised during kbase_device_init.
*
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
*/
void kbase_device_term(struct kbase_device *kbdev);

View File

@ -0,0 +1,78 @@
/*
*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <mali_kbase.h>
typedef int kbase_device_init_method(struct kbase_device *kbdev);
typedef void kbase_device_term_method(struct kbase_device *kbdev);
/**
* struct kbase_device_init - Device init/term methods.
* @init: Function pointer to a initialise method.
* @term: Function pointer to a terminate method.
* @err_mes: Error message to be printed when init method fails.
*/
struct kbase_device_init {
kbase_device_init_method *init;
kbase_device_term_method *term;
char *err_mes;
};
int kbase_device_vinstr_init(struct kbase_device *kbdev);
void kbase_device_vinstr_term(struct kbase_device *kbdev);
int kbase_device_timeline_init(struct kbase_device *kbdev);
void kbase_device_timeline_term(struct kbase_device *kbdev);
int kbase_device_hwcnt_backend_gpu_init(struct kbase_device *kbdev);
void kbase_device_hwcnt_backend_gpu_term(struct kbase_device *kbdev);
int kbase_device_hwcnt_context_init(struct kbase_device *kbdev);
void kbase_device_hwcnt_context_term(struct kbase_device *kbdev);
int kbase_device_hwcnt_virtualizer_init(struct kbase_device *kbdev);
void kbase_device_hwcnt_virtualizer_term(struct kbase_device *kbdev);
int kbase_device_list_init(struct kbase_device *kbdev);
void kbase_device_list_term(struct kbase_device *kbdev);
int kbase_device_io_history_init(struct kbase_device *kbdev);
void kbase_device_io_history_term(struct kbase_device *kbdev);
int kbase_device_misc_register(struct kbase_device *kbdev);
void kbase_device_misc_deregister(struct kbase_device *kbdev);
void kbase_device_id_init(struct kbase_device *kbdev);
/**
* kbase_device_early_init - Perform any device-specific initialization.
* @kbdev: Device pointer
*
* Return: 0 on success, or an error code on failure.
*/
int kbase_device_early_init(struct kbase_device *kbdev);
/**
* kbase_device_early_term - Perform any device-specific termination.
* @kbdev: Device pointer
*/
void kbase_device_early_term(struct kbase_device *kbdev);

View File

@ -0,0 +1,181 @@
/*
*
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <mali_kbase.h>
#include "../mali_kbase_gpu_fault.h"
const char *kbase_gpu_exception_name(u32 const exception_code)
{
const char *e;
switch (exception_code) {
/* Non-Fault Status code */
case 0x00:
e = "NOT_STARTED/IDLE/OK";
break;
case 0x01:
e = "DONE";
break;
case 0x02:
e = "INTERRUPTED";
break;
case 0x03:
e = "STOPPED";
break;
case 0x04:
e = "TERMINATED";
break;
case 0x08:
e = "ACTIVE";
break;
/* Job exceptions */
case 0x40:
e = "JOB_CONFIG_FAULT";
break;
case 0x41:
e = "JOB_POWER_FAULT";
break;
case 0x42:
e = "JOB_READ_FAULT";
break;
case 0x43:
e = "JOB_WRITE_FAULT";
break;
case 0x44:
e = "JOB_AFFINITY_FAULT";
break;
case 0x48:
e = "JOB_BUS_FAULT";
break;
case 0x50:
e = "INSTR_INVALID_PC";
break;
case 0x51:
e = "INSTR_INVALID_ENC";
break;
case 0x52:
e = "INSTR_TYPE_MISMATCH";
break;
case 0x53:
e = "INSTR_OPERAND_FAULT";
break;
case 0x54:
e = "INSTR_TLS_FAULT";
break;
case 0x55:
e = "INSTR_BARRIER_FAULT";
break;
case 0x56:
e = "INSTR_ALIGN_FAULT";
break;
case 0x58:
e = "DATA_INVALID_FAULT";
break;
case 0x59:
e = "TILE_RANGE_FAULT";
break;
case 0x5A:
e = "ADDR_RANGE_FAULT";
break;
case 0x60:
e = "OUT_OF_MEMORY";
break;
/* GPU exceptions */
case 0x80:
e = "DELAYED_BUS_FAULT";
break;
case 0x88:
e = "SHAREABILITY_FAULT";
break;
/* MMU exceptions */
case 0xC0:
case 0xC1:
case 0xC2:
case 0xC3:
case 0xC4:
case 0xC5:
case 0xC6:
case 0xC7:
e = "TRANSLATION_FAULT";
break;
case 0xC8:
e = "PERMISSION_FAULT";
break;
case 0xC9:
case 0xCA:
case 0xCB:
case 0xCC:
case 0xCD:
case 0xCE:
case 0xCF:
e = "PERMISSION_FAULT";
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
case 0xD4:
case 0xD5:
case 0xD6:
case 0xD7:
e = "TRANSTAB_BUS_FAULT";
break;
case 0xD8:
e = "ACCESS_FLAG";
break;
case 0xD9:
case 0xDA:
case 0xDB:
case 0xDC:
case 0xDD:
case 0xDE:
case 0xDF:
e = "ACCESS_FLAG";
break;
case 0xE0:
case 0xE1:
case 0xE2:
case 0xE3:
case 0xE4:
case 0xE5:
case 0xE6:
case 0xE7:
e = "ADDRESS_SIZE_FAULT";
break;
case 0xE8:
case 0xE9:
case 0xEA:
case 0xEB:
case 0xEC:
case 0xED:
case 0xEE:
case 0xEF:
e = "MEMORY_ATTRIBUTES_FAULT";
break;
default:
e = "UNKNOWN";
break;
};
return e;
}

View File

@ -20,15 +20,69 @@
*
*/
#ifndef _MIDG_REGMAP_JM_H_
#define _MIDG_REGMAP_JM_H_
#ifndef _KBASE_GPU_REGMAP_JM_H_
#define _KBASE_GPU_REGMAP_JM_H_
/* Set to implementation defined, outer caching */
#define AS_MEMATTR_AARCH64_OUTER_IMPL_DEF 0x88ull
/* Set to write back memory, outer caching */
#define AS_MEMATTR_AARCH64_OUTER_WA 0x8Dull
/* Set to inner non-cacheable, outer-non-cacheable
* Setting defined by the alloc bits is ignored, but set to a valid encoding:
* - no-alloc on read
* - no alloc on write
*/
#define AS_MEMATTR_AARCH64_NON_CACHEABLE 0x4Cull
/* Symbols for default MEMATTR to use
* Default is - HW implementation defined caching
*/
#define AS_MEMATTR_INDEX_DEFAULT 0
#define AS_MEMATTR_INDEX_DEFAULT_ACE 3
/* HW implementation defined caching */
#define AS_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY 0
/* Force cache on */
#define AS_MEMATTR_INDEX_FORCE_TO_CACHE_ALL 1
/* Write-alloc */
#define AS_MEMATTR_INDEX_WRITE_ALLOC 2
/* Outer coherent, inner implementation defined policy */
#define AS_MEMATTR_INDEX_OUTER_IMPL_DEF 3
/* Outer coherent, write alloc inner */
#define AS_MEMATTR_INDEX_OUTER_WA 4
/* Normal memory, inner non-cacheable, outer non-cacheable (ARMv8 mode only) */
#define AS_MEMATTR_INDEX_NON_CACHEABLE 5
/* GPU control registers */
#define CORE_FEATURES 0x008 /* (RO) Shader Core Features */
#define JS_PRESENT 0x01C /* (RO) Job slots present */
#define LATEST_FLUSH 0x038 /* (RO) Flush ID of latest clean-and-invalidate operation */
#define GROUPS_L2_COHERENT (1 << 0) /* Cores groups are l2 coherent */
#define LATEST_FLUSH 0x038 /* (RO) Flush ID of latest
* clean-and-invalidate operation
*/
#define PRFCNT_BASE_LO 0x060 /* (RW) Performance counter memory
* region base address, low word
*/
#define PRFCNT_BASE_HI 0x064 /* (RW) Performance counter memory
* region base address, high word
*/
#define PRFCNT_CONFIG 0x068 /* (RW) Performance counter
* configuration
*/
#define PRFCNT_JM_EN 0x06C /* (RW) Performance counter enable
* flags for Job Manager
*/
#define PRFCNT_SHADER_EN 0x070 /* (RW) Performance counter enable
* flags for shader cores
*/
#define PRFCNT_TILER_EN 0x074 /* (RW) Performance counter enable
* flags for tiler
*/
#define PRFCNT_MMU_L2_EN 0x07C /* (RW) Performance counter enable
* flags for MMU/L2 cache
*/
#define JS0_FEATURES 0x0C0 /* (RO) Features of job slot 0 */
#define JS1_FEATURES 0x0C4 /* (RO) Features of job slot 1 */
@ -140,7 +194,7 @@
* The values are separated to avoid dependency of userspace and kernel code.
*/
/* Group of values representing the job status insead a particular fault */
/* Group of values representing the job status instead of a particular fault */
#define JS_STATUS_NO_EXCEPTION_BASE 0x00
#define JS_STATUS_INTERRUPTED (JS_STATUS_NO_EXCEPTION_BASE + 0x02) /* 0x02 means INTERRUPTED */
#define JS_STATUS_STOPPED (JS_STATUS_NO_EXCEPTION_BASE + 0x03) /* 0x03 means STOPPED */
@ -192,8 +246,6 @@
#define JM_JOB_THROTTLE_LIMIT_SHIFT (3)
#define JM_MAX_JOB_THROTTLE_LIMIT (0x3F)
#define JM_FORCE_COHERENCY_FEATURES_SHIFT (2)
#define JM_IDVS_GROUP_SIZE_SHIFT (16)
#define JM_MAX_IDVS_GROUP_SIZE (0x3F)
/* GPU_COMMAND values */
#define GPU_COMMAND_NOP 0x00 /* No operation, nothing happens */
@ -207,4 +259,4 @@
#define GPU_COMMAND_CLEAN_INV_CACHES 0x08 /* Clean and invalidate all caches */
#define GPU_COMMAND_SET_PROTECTED_MODE 0x09 /* Places the GPU in protected mode */
#endif /* _MIDG_REGMAP_JM_H_ */
#endif /* _KBASE_GPU_REGMAP_JM_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2017, 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,27 +20,22 @@
*
*/
/**
* Power management configuration
*
* Attached value: pointer to @ref kbase_pm_callback_conf
* Default value: See @ref kbase_pm_callback_conf
*/
#define POWER_MANAGEMENT_CALLBACKS (&pm_callbacks)
#include <mali_kbase.h>
#include <mali_kbase_defs.h>
/**
* Platform specific configuration functions
*
* Attached value: pointer to @ref kbase_platform_funcs_conf
* Default value: See @ref kbase_platform_funcs_conf
*/
#define PLATFORM_FUNCS (NULL)
extern struct kbase_pm_callback_conf pm_callbacks;
/**
* Autosuspend delay
*
* The delay time (in milliseconds) to be used for autosuspend
*/
#define AUTO_SUSPEND_DELAY (100)
const char *kbase_gpu_access_type_name(u32 fault_status)
{
switch (AS_FAULTSTATUS_ACCESS_TYPE_GET(fault_status)) {
case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC:
return "ATOMIC";
case AS_FAULTSTATUS_ACCESS_TYPE_READ:
return "READ";
case AS_FAULTSTATUS_ACCESS_TYPE_WRITE:
return "WRITE";
case AS_FAULTSTATUS_ACCESS_TYPE_EX:
return "EXECUTE";
default:
WARN_ON(1);
return NULL;
}
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2015, 2017, 2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,22 +20,12 @@
*
*/
#include <mali_kbase_config.h>
#ifndef _KBASE_GPU_H_
#define _KBASE_GPU_H_
static struct kbase_platform_config dummy_platform_config;
#include "mali_kbase_gpu_regmap.h"
#include "mali_kbase_gpu_fault.h"
#include "mali_kbase_gpu_coherency.h"
#include "mali_kbase_gpu_id.h"
struct kbase_platform_config *kbase_get_platform_config(void)
{
return &dummy_platform_config;
}
#ifndef CONFIG_OF
int kbase_platform_register(void)
{
return 0;
}
void kbase_platform_unregister(void)
{
}
#endif
#endif /* _KBASE_GPU_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2015-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,12 +20,12 @@
*
*/
#ifndef _MIDG_COHERENCY_H_
#define _MIDG_COHERENCY_H_
#ifndef _KBASE_GPU_COHERENCY_H_
#define _KBASE_GPU_COHERENCY_H_
#define COHERENCY_ACE_LITE 0
#define COHERENCY_ACE 1
#define COHERENCY_NONE 31
#define COHERENCY_FEATURE_BIT(x) (1 << (x))
#endif /* _MIDG_COHERENCY_H_ */
#endif /* _KBASE_GPU_COHERENCY_H_ */

View File

@ -0,0 +1,59 @@
/*
*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_GPU_FAULT_H_
#define _KBASE_GPU_FAULT_H_
/** Returns the name associated with a Mali exception code
*
* @exception_code: exception code
*
* This function is called from the interrupt handler when a GPU fault occurs.
*
* Return: name associated with the exception code
*/
const char *kbase_gpu_exception_name(u32 exception_code);
/** Returns the name associated with a Mali fatal exception code
*
* @fatal_exception_code: fatal exception code
*
* This function is called from the interrupt handler when a GPU fatal
* exception occurs.
*
* Return: name associated with the fatal exception code
*/
const char *kbase_gpu_fatal_exception_name(u32 const fatal_exception_code);
/**
* kbase_gpu_access_type_name - Convert MMU_AS_CONTROL.FAULTSTATUS.ACCESS_TYPE
* into string.
* @fault_status: value of FAULTSTATUS register.
*
* After MMU fault, this function can be used to get readable information about
* access_type of the MMU fault.
*
* Return: String of the access type.
*/
const char *kbase_gpu_access_type_name(u32 fault_status);
#endif /* _KBASE_GPU_FAULT_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2015-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2015-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -19,6 +19,7 @@
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_GPU_ID_H_
#define _KBASE_GPU_ID_H_
@ -97,12 +98,14 @@
#define GPU_ID2_PRODUCT_TNAX GPU_ID2_MODEL_MAKE(9, 1)
#define GPU_ID2_PRODUCT_TBEX GPU_ID2_MODEL_MAKE(9, 2)
#define GPU_ID2_PRODUCT_LBEX GPU_ID2_MODEL_MAKE(9, 4)
#define GPU_ID2_PRODUCT_TULX GPU_ID2_MODEL_MAKE(10, 0)
#define GPU_ID2_PRODUCT_TDUX GPU_ID2_MODEL_MAKE(10, 1)
#define GPU_ID2_PRODUCT_TODX GPU_ID2_MODEL_MAKE(10, 2)
#define GPU_ID2_PRODUCT_TIDX GPU_ID2_MODEL_MAKE(10, 3)
#define GPU_ID2_PRODUCT_TGRX GPU_ID2_MODEL_MAKE(10, 3)
#define GPU_ID2_PRODUCT_TVAX GPU_ID2_MODEL_MAKE(10, 4)
#define GPU_ID2_PRODUCT_LODX GPU_ID2_MODEL_MAKE(10, 5)
#define GPU_ID2_PRODUCT_LODX GPU_ID2_MODEL_MAKE(10, 7)
#define GPU_ID2_PRODUCT_TTUX GPU_ID2_MODEL_MAKE(11, 2)
#define GPU_ID2_PRODUCT_LTUX GPU_ID2_MODEL_MAKE(11, 3)
#define GPU_ID2_PRODUCT_TE2X GPU_ID2_MODEL_MAKE(11, 1)
/* Helper macro to create a GPU_ID assuming valid values for id, major,
minor, status */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -20,12 +20,12 @@
*
*/
#ifndef _MIDG_REGMAP_H_
#define _MIDG_REGMAP_H_
#ifndef _KBASE_GPU_REGMAP_H_
#define _KBASE_GPU_REGMAP_H_
#include "mali_midg_coherency.h"
#include "mali_kbase_gpu_coherency.h"
#include "mali_kbase_gpu_id.h"
#include "mali_midg_regmap_jm.h"
#include "backend/mali_kbase_gpu_regmap_jm.h"
/* Begin Register Offsets */
/* GPU control registers */
@ -54,18 +54,15 @@
#define L2_CONFIG 0x048 /* (RW) Level 2 cache configuration */
#define GROUPS_L2_COHERENT (1 << 0) /* Cores groups are l2 coherent */
#define SUPER_L2_COHERENT (1 << 1) /* Shader cores within a core
* supergroup are l2 coherent
*/
#define PWR_KEY 0x050 /* (WO) Power manager key register */
#define PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */
#define PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */
#define PRFCNT_BASE_LO 0x060 /* (RW) Performance counter memory region base address, low word */
#define PRFCNT_BASE_HI 0x064 /* (RW) Performance counter memory region base address, high word */
#define PRFCNT_CONFIG 0x068 /* (RW) Performance counter configuration */
#define PRFCNT_JM_EN 0x06C /* (RW) Performance counter enable flags for Job Manager */
#define PRFCNT_SHADER_EN 0x070 /* (RW) Performance counter enable flags for shader cores */
#define PRFCNT_TILER_EN 0x074 /* (RW) Performance counter enable flags for tiler */
#define PRFCNT_MMU_L2_EN 0x07C /* (RW) Performance counter enable flags for MMU/L2 cache */
#define CYCLE_COUNT_LO 0x090 /* (RO) Cycle counter, low word */
#define CYCLE_COUNT_HI 0x094 /* (RO) Cycle counter, high word */
#define TIMESTAMP_LO 0x098 /* (RO) Global time stamp counter, low word */
@ -235,9 +232,17 @@
#define PRFCNT_SAMPLE_COMPLETED (1 << 16) /* Set when a performance count sample has completed. */
#define CLEAN_CACHES_COMPLETED (1 << 17) /* Set when a cache clean operation has completed. */
#define GPU_IRQ_REG_ALL (GPU_FAULT | MULTIPLE_GPU_FAULTS | RESET_COMPLETED \
/* Include POWER_CHANGED_SINGLE in debug builds for use in irq latency test.
*/
#define GPU_IRQ_REG_COMMON (GPU_FAULT | MULTIPLE_GPU_FAULTS | RESET_COMPLETED \
| POWER_CHANGED_ALL | PRFCNT_SAMPLE_COMPLETED)
#ifdef CONFIG_MALI_BIFROST_DEBUG
#define GPU_IRQ_REG_ALL (GPU_IRQ_REG_COMMON | POWER_CHANGED_SINGLE)
#else /* CONFIG_MALI_BIFROST_DEBUG */
#define GPU_IRQ_REG_ALL (GPU_IRQ_REG_COMMON)
#endif /* CONFIG_MALI_BIFROST_DEBUG */
/*
* MMU_IRQ_RAWSTAT register values. Values are valid also for
* MMU_IRQ_CLEAR, MMU_IRQ_MASK, MMU_IRQ_STATUS registers.
@ -281,11 +286,25 @@
#define AS_FAULTSTATUS_EXCEPTION_CODE_ADDRESS_SIZE_FAULT (0x4<<3)
#define AS_FAULTSTATUS_EXCEPTION_CODE_MEMORY_ATTRIBUTES_FAULT (0x5<<3)
#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3<<8)
#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0<<8)
#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1<<8)
#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2<<8)
#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3<<8)
#define AS_FAULTSTATUS_EXCEPTION_TYPE_SHIFT 0
#define AS_FAULTSTATUS_EXCEPTION_TYPE_MASK (0xFF << AS_FAULTSTATUS_EXCEPTION_TYPE_SHIFT)
#define AS_FAULTSTATUS_EXCEPTION_TYPE_GET(reg_val) \
(((reg_val)&AS_FAULTSTATUS_EXCEPTION_TYPE_MASK) >> AS_FAULTSTATUS_EXCEPTION_TYPE_SHIFT)
#define AS_FAULTSTATUS_ACCESS_TYPE_SHIFT 8
#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << AS_FAULTSTATUS_ACCESS_TYPE_SHIFT)
#define AS_FAULTSTATUS_ACCESS_TYPE_GET(reg_val) \
(((reg_val)&AS_FAULTSTATUS_ACCESS_TYPE_MASK) >> AS_FAULTSTATUS_ACCESS_TYPE_SHIFT)
#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0)
#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1)
#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2)
#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3)
#define AS_FAULTSTATUS_SOURCE_ID_SHIFT 16
#define AS_FAULTSTATUS_SOURCE_ID_MASK (0xFFFF << AS_FAULTSTATUS_SOURCE_ID_SHIFT)
#define AS_FAULTSTATUS_SOURCE_ID_GET(reg_val) \
(((reg_val)&AS_FAULTSTATUS_SOURCE_ID_MASK) >> AS_FAULTSTATUS_SOURCE_ID_SHIFT)
/*
* Begin MMU TRANSCFG register values
@ -353,17 +372,6 @@
/* Inner write-alloc cache setup, no outer caching */
#define AS_MEMATTR_WRITE_ALLOC 0x8Dull
/* Set to implementation defined, outer caching */
#define AS_MEMATTR_AARCH64_OUTER_IMPL_DEF 0x88ull
/* Set to write back memory, outer caching */
#define AS_MEMATTR_AARCH64_OUTER_WA 0x8Dull
/* Set to inner non-cacheable, outer-non-cacheable
* Setting defined by the alloc bits is ignored, but set to a valid encoding:
* - no-alloc on read
* - no alloc on write
*/
#define AS_MEMATTR_AARCH64_NON_CACHEABLE 0x4Cull
/* Use GPU implementation-defined caching policy. */
#define AS_MEMATTR_LPAE_IMPL_DEF_CACHE_POLICY 0x48ull
/* The attribute set to force all resources to be cached. */
@ -380,24 +388,6 @@
*/
#define AS_MEMATTR_LPAE_NON_CACHEABLE_RESERVED
/* Symbols for default MEMATTR to use
* Default is - HW implementation defined caching */
#define AS_MEMATTR_INDEX_DEFAULT 0
#define AS_MEMATTR_INDEX_DEFAULT_ACE 3
/* HW implementation defined caching */
#define AS_MEMATTR_INDEX_IMPL_DEF_CACHE_POLICY 0
/* Force cache on */
#define AS_MEMATTR_INDEX_FORCE_TO_CACHE_ALL 1
/* Write-alloc */
#define AS_MEMATTR_INDEX_WRITE_ALLOC 2
/* Outer coherent, inner implementation defined policy */
#define AS_MEMATTR_INDEX_OUTER_IMPL_DEF 3
/* Outer coherent, write alloc inner */
#define AS_MEMATTR_INDEX_OUTER_WA 4
/* Normal memory, inner non-cacheable, outer non-cacheable (ARMv8 mode only) */
#define AS_MEMATTR_INDEX_NON_CACHEABLE 5
/* L2_MMU_CONFIG register */
#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT (23)
#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY (0x1 << L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT)
@ -440,5 +430,8 @@
#define L2_CONFIG_HASH_MASK (0xFFul << L2_CONFIG_HASH_SHIFT)
/* End L2_CONFIG register */
/* IDVS_GROUP register */
#define IDVS_GROUP_SIZE_SHIFT (16)
#define IDVS_GROUP_MAX_SIZE (0x3F)
#endif /* _MIDG_REGMAP_H_ */
#endif /* _KBASE_GPU_REGMAP_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,818 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Definitions (types, defines, etcs) specific to Job Manager Kbase.
* They are placed here to allow the hierarchy of header files to work.
*/
#ifndef _KBASE_JM_DEFS_H_
#define _KBASE_JM_DEFS_H_
#include "mali_kbase_js_defs.h"
/* Dump Job slot trace on error (only active if KBASE_KTRACE_ENABLE != 0) */
#define KBASE_KTRACE_DUMP_ON_JOB_SLOT_ERROR 1
/*
* Number of milliseconds before resetting the GPU when a job cannot be "zapped"
* from the hardware. Note that the time is actually
* ZAP_TIMEOUT+SOFT_STOP_RESET_TIMEOUT between the context zap starting and
* the GPU actually being reset to give other contexts time for their jobs
* to be soft-stopped and removed from the hardware before resetting.
*/
#define ZAP_TIMEOUT 1000
/*
* Prevent soft-stops from occurring in scheduling situations
*
* This is not due to HW issues, but when scheduling is desired to be more
* predictable.
*
* Therefore, soft stop may still be disabled due to HW issues.
*
* Soft stop will still be used for non-scheduling purposes e.g. when
* terminating a context.
*
* if not in use, define this value to 0 instead of being undefined.
*/
#define KBASE_DISABLE_SCHEDULING_SOFT_STOPS 0
/*
* Prevent hard-stops from occurring in scheduling situations
*
* This is not due to HW issues, but when scheduling is desired to be more
* predictable.
*
* Hard stop will still be used for non-scheduling purposes e.g. when
* terminating a context.
*
* if not in use, define this value to 0 instead of being undefined.
*/
#define KBASE_DISABLE_SCHEDULING_HARD_STOPS 0
/* Atom has been previously soft-stopped */
#define KBASE_KATOM_FLAG_BEEN_SOFT_STOPPED (1<<1)
/* Atom has been previously retried to execute */
#define KBASE_KATOM_FLAGS_RERUN (1<<2)
/* Atom submitted with JOB_CHAIN_FLAG bit set in JS_CONFIG_NEXT register, helps
* to disambiguate short-running job chains during soft/hard stopping of jobs
*/
#define KBASE_KATOM_FLAGS_JOBCHAIN (1<<3)
/* Atom has been previously hard-stopped. */
#define KBASE_KATOM_FLAG_BEEN_HARD_STOPPED (1<<4)
/* Atom has caused us to enter disjoint state */
#define KBASE_KATOM_FLAG_IN_DISJOINT (1<<5)
/* Atom blocked on cross-slot dependency */
#define KBASE_KATOM_FLAG_X_DEP_BLOCKED (1<<7)
/* Atom has fail dependency on cross-slot dependency */
#define KBASE_KATOM_FLAG_FAIL_BLOCKER (1<<8)
/* Atom is currently in the list of atoms blocked on cross-slot dependencies */
#define KBASE_KATOM_FLAG_JSCTX_IN_X_DEP_LIST (1<<9)
/* Atom is currently holding a context reference */
#define KBASE_KATOM_FLAG_HOLDING_CTX_REF (1<<10)
/* Atom requires GPU to be in protected mode */
#define KBASE_KATOM_FLAG_PROTECTED (1<<11)
/* Atom has been stored in runnable_tree */
#define KBASE_KATOM_FLAG_JSCTX_IN_TREE (1<<12)
/* Atom is waiting for L2 caches to power up in order to enter protected mode */
#define KBASE_KATOM_FLAG_HOLDING_L2_REF_PROT (1<<13)
/* SW related flags about types of JS_COMMAND action
* NOTE: These must be masked off by JS_COMMAND_MASK
*/
/* This command causes a disjoint event */
#define JS_COMMAND_SW_CAUSES_DISJOINT 0x100
/* Bitmask of all SW related flags */
#define JS_COMMAND_SW_BITS (JS_COMMAND_SW_CAUSES_DISJOINT)
#if (JS_COMMAND_SW_BITS & JS_COMMAND_MASK)
#error "JS_COMMAND_SW_BITS not masked off by JS_COMMAND_MASK." \
"Must update JS_COMMAND_SW_<..> bitmasks"
#endif
/* Soft-stop command that causes a Disjoint event. This of course isn't
* entirely masked off by JS_COMMAND_MASK
*/
#define JS_COMMAND_SOFT_STOP_WITH_SW_DISJOINT \
(JS_COMMAND_SW_CAUSES_DISJOINT | JS_COMMAND_SOFT_STOP)
#define KBASEP_ATOM_ID_INVALID BASE_JD_ATOM_COUNT
/* Serialize atoms within a slot (ie only one atom per job slot) */
#define KBASE_SERIALIZE_INTRA_SLOT (1 << 0)
/* Serialize atoms between slots (ie only one job slot running at any time) */
#define KBASE_SERIALIZE_INTER_SLOT (1 << 1)
/* Reset the GPU after each atom completion */
#define KBASE_SERIALIZE_RESET (1 << 2)
#ifdef CONFIG_DEBUG_FS
/**
* struct base_job_fault_event - keeps track of the atom which faulted or which
* completed after the faulty atom but before the
* debug data for faulty atom was dumped.
*
* @event_code: event code for the atom, should != BASE_JD_EVENT_DONE for
* the atom which faulted.
* @katom: pointer to the atom for which job fault occurred or which
* completed after the faulty atom.
* @job_fault_work: work item, queued only for the faulty atom, which waits for
* the dumping to get completed and then does the bottom half
* of job done for the atoms which followed the faulty atom.
* @head: List head used to store the atom in the global list of
* faulty atoms or context specific list of atoms which got
* completed during the dump.
* @reg_offset: offset of the register to be dumped next, only applicable
* for the faulty atom.
*/
struct base_job_fault_event {
u32 event_code;
struct kbase_jd_atom *katom;
struct work_struct job_fault_work;
struct list_head head;
int reg_offset;
};
#endif
/**
* struct kbase_jd_atom_dependency - Contains the dependency info for an atom.
* @atom: pointer to the dependee atom.
* @dep_type: type of dependency on the dependee @atom, i.e. order or data
* dependency. BASE_JD_DEP_TYPE_INVALID indicates no dependency.
*/
struct kbase_jd_atom_dependency {
struct kbase_jd_atom *atom;
u8 dep_type;
};
/**
* kbase_jd_katom_dep_atom - Retrieves a read-only reference to the
* dependee atom.
* @dep: pointer to the dependency info structure.
*
* Return: readonly reference to dependee atom.
*/
static inline const struct kbase_jd_atom *
kbase_jd_katom_dep_atom(const struct kbase_jd_atom_dependency *dep)
{
LOCAL_ASSERT(dep != NULL);
return (const struct kbase_jd_atom *)(dep->atom);
}
/**
* kbase_jd_katom_dep_type - Retrieves the dependency type info
*
* @dep: pointer to the dependency info structure.
*
* Return: the type of dependency there is on the dependee atom.
*/
static inline u8 kbase_jd_katom_dep_type(
const struct kbase_jd_atom_dependency *dep)
{
LOCAL_ASSERT(dep != NULL);
return dep->dep_type;
}
/**
* kbase_jd_katom_dep_set - sets up the dependency info structure
* as per the values passed.
* @const_dep: pointer to the dependency info structure to be setup.
* @a: pointer to the dependee atom.
* @type: type of dependency there is on the dependee atom.
*/
static inline void kbase_jd_katom_dep_set(
const struct kbase_jd_atom_dependency *const_dep,
struct kbase_jd_atom *a, u8 type)
{
struct kbase_jd_atom_dependency *dep;
LOCAL_ASSERT(const_dep != NULL);
dep = (struct kbase_jd_atom_dependency *)const_dep;
dep->atom = a;
dep->dep_type = type;
}
/**
* kbase_jd_katom_dep_clear - resets the dependency info structure
*
* @const_dep: pointer to the dependency info structure to be setup.
*/
static inline void kbase_jd_katom_dep_clear(
const struct kbase_jd_atom_dependency *const_dep)
{
struct kbase_jd_atom_dependency *dep;
LOCAL_ASSERT(const_dep != NULL);
dep = (struct kbase_jd_atom_dependency *)const_dep;
dep->atom = NULL;
dep->dep_type = BASE_JD_DEP_TYPE_INVALID;
}
/**
* enum kbase_atom_gpu_rb_state - The state of an atom, pertinent after it
* becomes runnable, with respect to job slot
* ringbuffer/fifo.
* @KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB: Atom not currently present in slot fifo,
* which implies that either atom has not become
* runnable due to dependency or has completed
* the execution on GPU.
* @KBASE_ATOM_GPU_RB_WAITING_BLOCKED: Atom has been added to slot fifo but is
* blocked due to cross slot dependency,
* can't be submitted to GPU.
* @KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV: Atom has been added to slot
* fifo but is waiting for the completion of
* previously added atoms in current & other
* slots, as their protected mode requirements
* do not match with the current atom.
* @KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION: Atom is in slot fifo
* and is waiting for completion of protected
* mode transition, needed before the atom is
* submitted to GPU.
* @KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE: Atom is in slot fifo but is
* waiting for the cores, which are needed to
* execute the job chain represented by the atom,
* to become available
* @KBASE_ATOM_GPU_RB_READY: Atom is in slot fifo and can be submitted to
* GPU.
* @KBASE_ATOM_GPU_RB_SUBMITTED: Atom is in slot fifo and has been submitted
* to GPU.
* @KBASE_ATOM_GPU_RB_RETURN_TO_JS: Atom must be returned to JS due to some
* failure, but only after the previously added
* atoms in fifo have completed or have also
* been returned to JS.
*/
enum kbase_atom_gpu_rb_state {
KBASE_ATOM_GPU_RB_NOT_IN_SLOT_RB,
KBASE_ATOM_GPU_RB_WAITING_BLOCKED,
KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_PREV,
KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION,
KBASE_ATOM_GPU_RB_WAITING_FOR_CORE_AVAILABLE,
KBASE_ATOM_GPU_RB_READY,
KBASE_ATOM_GPU_RB_SUBMITTED,
KBASE_ATOM_GPU_RB_RETURN_TO_JS = -1
};
/**
* enum kbase_atom_enter_protected_state - The state of an atom with respect to
* the preparation for GPU's entry into protected mode,
* becomes pertinent only after atom's state with respect
* to slot ringbuffer is
* KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION
* @KBASE_ATOM_ENTER_PROTECTED_CHECK: Starting state. Check if there are any
* atoms currently submitted to GPU and protected mode
* transition is not already in progress.
* @KBASE_ATOM_ENTER_PROTECTED_HWCNT: Wait for hardware counter context to
* become disabled before entry into protected mode.
* @KBASE_ATOM_ENTER_PROTECTED_IDLE_L2: Wait for the L2 to become idle in
* preparation for the coherency change. L2 shall be
* powered down and GPU shall come out of fully
* coherent mode before entering protected mode.
* @KBASE_ATOM_ENTER_PROTECTED_SET_COHERENCY: Prepare coherency change;
* for BASE_HW_ISSUE_TGOX_R1_1234 also request L2 power on
* so that coherency register contains correct value when
* GPU enters protected mode.
* @KBASE_ATOM_ENTER_PROTECTED_FINISHED: End state; for
* BASE_HW_ISSUE_TGOX_R1_1234 check
* that L2 is powered up and switch GPU to protected mode.
*/
enum kbase_atom_enter_protected_state {
/*
* NOTE: The integer value of this must match
* KBASE_ATOM_EXIT_PROTECTED_CHECK.
*/
KBASE_ATOM_ENTER_PROTECTED_CHECK = 0,
KBASE_ATOM_ENTER_PROTECTED_HWCNT,
KBASE_ATOM_ENTER_PROTECTED_IDLE_L2,
KBASE_ATOM_ENTER_PROTECTED_SET_COHERENCY,
KBASE_ATOM_ENTER_PROTECTED_FINISHED,
};
/**
* enum kbase_atom_exit_protected_state - The state of an atom with respect to
* the preparation for GPU's exit from protected mode,
* becomes pertinent only after atom's state with respect
* to slot ngbuffer is
* KBASE_ATOM_GPU_RB_WAITING_PROTECTED_MODE_TRANSITION
* @KBASE_ATOM_EXIT_PROTECTED_CHECK: Starting state. Check if there are any
* atoms currently submitted to GPU and protected mode
* transition is not already in progress.
* @KBASE_ATOM_EXIT_PROTECTED_IDLE_L2: Wait for the L2 to become idle in
* preparation for the reset, as exiting protected mode
* requires a reset.
* @KBASE_ATOM_EXIT_PROTECTED_RESET: Issue the reset to trigger exit from
* protected mode
* @KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT: End state, Wait for the reset to
* complete
*/
enum kbase_atom_exit_protected_state {
/*
* NOTE: The integer value of this must match
* KBASE_ATOM_ENTER_PROTECTED_CHECK.
*/
KBASE_ATOM_EXIT_PROTECTED_CHECK = 0,
KBASE_ATOM_EXIT_PROTECTED_IDLE_L2,
KBASE_ATOM_EXIT_PROTECTED_RESET,
KBASE_ATOM_EXIT_PROTECTED_RESET_WAIT,
};
/**
* struct kbase_ext_res - Contains the info for external resources referred
* by an atom, which have been mapped on GPU side.
* @gpu_address: Start address of the memory region allocated for
* the resource from GPU virtual address space.
* @alloc: pointer to physical pages tracking object, set on
* mapping the external resource on GPU side.
*/
struct kbase_ext_res {
u64 gpu_address;
struct kbase_mem_phy_alloc *alloc;
};
/**
* struct kbase_jd_atom - object representing the atom, containing the complete
* state and attributes of an atom.
* @work: work item for the bottom half processing of the atom,
* by JD or JS, after it got executed on GPU or the
* input fence got signaled
* @start_timestamp: time at which the atom was submitted to the GPU, by
* updating the JS_HEAD_NEXTn register.
* @udata: copy of the user data sent for the atom in
* base_jd_submit.
* @kctx: Pointer to the base context with which the atom is
* associated.
* @dep_head: Array of 2 list heads, pointing to the two list of
* atoms
* which are blocked due to dependency on this atom.
* @dep_item: Array of 2 list heads, used to store the atom in the
* list of other atoms depending on the same dependee
* atom.
* @dep: Array containing the dependency info for the 2 atoms
* on which the atom depends upon.
* @jd_item: List head used during job dispatch job_done
* processing - as dependencies may not be entirely
* resolved at this point,
* we need to use a separate list head.
* @in_jd_list: flag set to true if atom's @jd_item is currently on
* a list, prevents atom being processed twice.
* @jit_ids: Zero-terminated array of IDs of just-in-time memory
* allocations written to by the atom. When the atom
* completes, the value stored at the
* &struct_base_jit_alloc_info.heap_info_gpu_addr of
* each allocation is read in order to enforce an
* overall physical memory usage limit.
* @nr_extres: number of external resources referenced by the atom.
* @extres: pointer to the location containing info about
* @nr_extres external resources referenced by the atom.
* @device_nr: indicates the coregroup with which the atom is
* associated, when
* BASE_JD_REQ_SPECIFIC_COHERENT_GROUP specified.
* @jc: GPU address of the job-chain.
* @softjob_data: Copy of data read from the user space buffer that @jc
* points to.
* @fence: Stores either an input or output sync fence,
* depending on soft-job type
* @sync_waiter: Pointer to the sync fence waiter structure passed to
* the callback function on signaling of the input
* fence.
* @dma_fence: object containing pointers to both input & output
* fences and other related members used for explicit
* sync through soft jobs and for the implicit
* synchronization required on access to external
* resources.
* @event_code: Event code for the job chain represented by the atom,
* both HW and low-level SW events are represented by
* event codes.
* @core_req: bitmask of BASE_JD_REQ_* flags specifying either
* Hw or Sw requirements for the job chain represented
* by the atom.
* @ticks: Number of scheduling ticks for which atom has been
* running on the GPU.
* @sched_priority: Priority of the atom for Job scheduling, as per the
* KBASE_JS_ATOM_SCHED_PRIO_*.
* @completed: Wait queue to wait upon for the completion of atom.
* @status: Indicates at high level at what stage the atom is in,
* as per KBASE_JD_ATOM_STATE_*, that whether it is not
* in use or its queued in JD or given to JS or
* submitted to Hw or it completed the execution on Hw.
* @work_id: used for GPU tracepoints, its a snapshot of the
* 'work_id' counter in kbase_jd_context which is
* incremented on every call to base_jd_submit.
* @slot_nr: Job slot chosen for the atom.
* @atom_flags: bitmask of KBASE_KATOM_FLAG* flags capturing the
* excat low level state of the atom.
* @gpu_rb_state: bitmnask of KBASE_ATOM_GPU_RB_* flags, precisely
* tracking atom's state after it has entered
* Job scheduler on becoming runnable. Atom
* could be blocked due to cross slot dependency
* or waiting for the shader cores to become available
* or waiting for protected mode transitions to
* complete.
* @need_cache_flush_cores_retained: flag indicating that manual flush of GPU
* cache is needed for the atom and the shader cores
* used for atom have been kept on.
* @blocked: flag indicating that atom's resubmission to GPU is
* blocked till the work item is scheduled to return the
* atom to JS.
* @pre_dep: Pointer to atom that this atom has same-slot
* dependency on
* @post_dep: Pointer to atom that has same-slot dependency on
* this atom
* @x_pre_dep: Pointer to atom that this atom has cross-slot
* dependency on
* @x_post_dep: Pointer to atom that has cross-slot dependency on
* this atom
* @flush_id: The GPU's flush count recorded at the time of
* submission,
* used for the cache flush optimization
* @fault_event: Info for dumping the debug data on Job fault.
* @queue: List head used for 4 different purposes :
* Adds atom to the list of dma-buf fence waiting atoms.
* Adds atom to the list of atoms blocked due to cross
* slot dependency.
* Adds atom to the list of softjob atoms for which JIT
* allocation has been deferred
* Adds atom to the list of softjob atoms waiting for
* the signaling of fence.
* @jit_node: Used to keep track of all JIT free/alloc jobs in
* submission order
* @jit_blocked: Flag indicating that JIT allocation requested through
* softjob atom will be reattempted after the impending
* free of other active JIT allocations.
* @will_fail_event_code: If non-zero, this indicates that the atom will fail
* with the set event_code when the atom is processed.
* Used for special handling of atoms, which have a data
* dependency on the failed atoms.
* @protected_state: State of the atom, as per
* KBASE_ATOM_(ENTER|EXIT)_PROTECTED_*,
* when transitioning into or out of protected mode.
* Atom will be either entering or exiting the
* protected mode.
* @runnable_tree_node: The node added to context's job slot specific rb tree
* when the atom becomes runnable.
* @age: Age of atom relative to other atoms in the context,
* is snapshot of the age_count counter in kbase
* context.
*/
struct kbase_jd_atom {
struct work_struct work;
ktime_t start_timestamp;
struct base_jd_udata udata;
struct kbase_context *kctx;
struct list_head dep_head[2];
struct list_head dep_item[2];
const struct kbase_jd_atom_dependency dep[2];
struct list_head jd_item;
bool in_jd_list;
#if MALI_JIT_PRESSURE_LIMIT
u8 jit_ids[2];
#endif /* MALI_JIT_PRESSURE_LIMIT */
u16 nr_extres;
struct kbase_ext_res *extres;
u32 device_nr;
u64 jc;
void *softjob_data;
#if defined(CONFIG_SYNC)
struct sync_fence *fence;
struct sync_fence_waiter sync_waiter;
#endif /* CONFIG_SYNC */
#if defined(CONFIG_MALI_BIFROST_DMA_FENCE) || defined(CONFIG_SYNC_FILE)
struct {
/* Use the functions/API defined in mali_kbase_fence.h to
* when working with this sub struct
*/
#if defined(CONFIG_SYNC_FILE)
/* Input fence */
#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
struct fence *fence_in;
#else
struct dma_fence *fence_in;
#endif
#endif
/* This points to the dma-buf output fence for this atom. If
* this is NULL then there is no fence for this atom and the
* following fields related to dma_fence may have invalid data.
*
* The context and seqno fields contain the details for this
* fence.
*
* This fence is signaled when the katom is completed,
* regardless of the event_code of the katom (signal also on
* failure).
*/
#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
struct fence *fence;
#else
struct dma_fence *fence;
#endif
/* The dma-buf fence context number for this atom. A unique
* context number is allocated to each katom in the context on
* context creation.
*/
unsigned int context;
/* The dma-buf fence sequence number for this atom. This is
* increased every time this katom uses dma-buf fence.
*/
atomic_t seqno;
/* This contains a list of all callbacks set up to wait on
* other fences. This atom must be held back from JS until all
* these callbacks have been called and dep_count have reached
* 0. The initial value of dep_count must be equal to the
* number of callbacks on this list.
*
* This list is protected by jctx.lock. Callbacks are added to
* this list when the atom is built and the wait are set up.
* All the callbacks then stay on the list until all callbacks
* have been called and the atom is queued, or cancelled, and
* then all callbacks are taken off the list and freed.
*/
struct list_head callbacks;
/* Atomic counter of number of outstandind dma-buf fence
* dependencies for this atom. When dep_count reaches 0 the
* atom may be queued.
*
* The special value "-1" may only be set after the count
* reaches 0, while holding jctx.lock. This indicates that the
* atom has been handled, either queued in JS or cancelled.
*
* If anyone but the dma-fence worker sets this to -1 they must
* ensure that any potentially queued worker must have
* completed before allowing the atom to be marked as unused.
* This can be done by flushing the fence work queue:
* kctx->dma_fence.wq.
*/
atomic_t dep_count;
} dma_fence;
#endif /* CONFIG_MALI_BIFROST_DMA_FENCE || CONFIG_SYNC_FILE */
/* Note: refer to kbasep_js_atom_retained_state, which will take a copy
* of some of the following members
*/
enum base_jd_event_code event_code;
base_jd_core_req core_req;
u8 jobslot;
u8 renderpass_id;
struct base_jd_fragment jc_fragment;
u32 ticks;
int sched_priority;
wait_queue_head_t completed;
enum kbase_jd_atom_state status;
#ifdef CONFIG_GPU_TRACEPOINTS
int work_id;
#endif
int slot_nr;
u32 atom_flags;
int retry_count;
enum kbase_atom_gpu_rb_state gpu_rb_state;
bool need_cache_flush_cores_retained;
atomic_t blocked;
struct kbase_jd_atom *pre_dep;
struct kbase_jd_atom *post_dep;
struct kbase_jd_atom *x_pre_dep;
struct kbase_jd_atom *x_post_dep;
u32 flush_id;
#ifdef CONFIG_DEBUG_FS
struct base_job_fault_event fault_event;
#endif
struct list_head queue;
struct list_head jit_node;
bool jit_blocked;
enum base_jd_event_code will_fail_event_code;
union {
enum kbase_atom_enter_protected_state enter;
enum kbase_atom_exit_protected_state exit;
} protected_state;
struct rb_node runnable_tree_node;
u32 age;
};
static inline bool kbase_jd_katom_is_protected(
const struct kbase_jd_atom *katom)
{
return (bool)(katom->atom_flags & KBASE_KATOM_FLAG_PROTECTED);
}
/*
* Theory of operations:
*
* Atom objects are statically allocated within the context structure.
*
* Each atom is the head of two lists, one for the "left" set of dependencies,
* one for the "right" set.
*/
#define KBASE_JD_DEP_QUEUE_SIZE 256
/**
* enum kbase_jd_renderpass_state - State of a renderpass
* @KBASE_JD_RP_COMPLETE: Unused or completed renderpass. Can only transition to
* START.
* @KBASE_JD_RP_START: Renderpass making a first attempt at tiling.
* Can transition to PEND_OOM or COMPLETE.
* @KBASE_JD_RP_PEND_OOM: Renderpass whose first attempt at tiling used too much
* memory and has a soft-stop pending. Can transition to
* OOM or COMPLETE.
* @KBASE_JD_RP_OOM: Renderpass whose first attempt at tiling used too much
* memory and therefore switched to incremental
* rendering. The fragment job chain is forced to run.
* Can only transition to RETRY.
* @KBASE_JD_RP_RETRY: Renderpass making a second or subsequent attempt at
* tiling. Can transition to RETRY_PEND_OOM or COMPLETE.
* @KBASE_JD_RP_RETRY_PEND_OOM: Renderpass whose second or subsequent attempt at
* tiling used too much memory again and has a
* soft-stop pending. Can transition to RETRY_OOM
* or COMPLETE.
* @KBASE_JD_RP_RETRY_OOM: Renderpass whose second or subsequent attempt at
* tiling used too much memory again. The fragment job
* chain is forced to run. Can only transition to RETRY.
*
* A state machine is used to control incremental rendering.
*/
enum kbase_jd_renderpass_state {
KBASE_JD_RP_COMPLETE, /* COMPLETE => START */
KBASE_JD_RP_START, /* START => PEND_OOM or COMPLETE */
KBASE_JD_RP_PEND_OOM, /* PEND_OOM => OOM or COMPLETE */
KBASE_JD_RP_OOM, /* OOM => RETRY */
KBASE_JD_RP_RETRY, /* RETRY => RETRY_PEND_OOM or
* COMPLETE
*/
KBASE_JD_RP_RETRY_PEND_OOM, /* RETRY_PEND_OOM => RETRY_OOM or
* COMPLETE
*/
KBASE_JD_RP_RETRY_OOM, /* RETRY_OOM => RETRY */
};
/**
* struct kbase_jd_renderpass - Data for a renderpass
* @state: Current state of the renderpass. If KBASE_JD_RP_COMPLETE then
* all other members are invalid.
* Both the job dispatcher context and hwaccess_lock must be
* locked to modify this so that it can be read with either
* (or both) locked.
* @start_katom: Address of the atom that is the start of a renderpass.
* Both the job dispatcher context and hwaccess_lock must be
* locked to modify this so that it can be read with either
* (or both) locked.
* @end_katom: Address of the atom that is the end of a renderpass, or NULL
* if that atom hasn't been added to the job scheduler yet.
* The job dispatcher context and hwaccess_lock must be
* locked to modify this so that it can be read with either
* (or both) locked.
* @oom_reg_list: A list of region structures which triggered out-of-memory.
* The hwaccess_lock must be locked to access this.
*
* Atoms tagged with BASE_JD_REQ_START_RENDERPASS or BASE_JD_REQ_END_RENDERPASS
* are associated with an object of this type, which is created and maintained
* by kbase to keep track of each renderpass.
*/
struct kbase_jd_renderpass {
enum kbase_jd_renderpass_state state;
struct kbase_jd_atom *start_katom;
struct kbase_jd_atom *end_katom;
struct list_head oom_reg_list;
};
/**
* struct kbase_jd_context - per context object encapsulating all the
* Job dispatcher related state.
* @lock: lock to serialize the updates made to the
* Job dispatcher state and kbase_jd_atom objects.
* @sched_info: Structure encapsulating all the Job scheduling
* info.
* @atoms: Array of the objects representing atoms,
* containing the complete state and attributes
* of an atom.
* @renderpasses: Array of renderpass state for incremental
* rendering, indexed by user-specified renderpass
* ID.
* @job_nr: Tracks the number of atoms being processed by the
* kbase. This includes atoms that are not tracked by
* scheduler: 'not ready to run' & 'dependency-only'
* jobs.
* @zero_jobs_wait: Waitq that reflects whether there are no jobs
* (including SW-only dependency jobs). This is set
* when no jobs are present on the ctx, and clear
* when there are jobs.
* This must be updated atomically with @job_nr.
* note: Job Dispatcher knows about more jobs than
* the Job Scheduler as it is unaware of jobs that
* are blocked on dependencies and SW-only dependency
* jobs. This waitq can be waited upon to find out
* when the context jobs are all done/cancelled
* (including those that might've been blocked
* on dependencies) - and so, whether it can be
* terminated. However, it should only be terminated
* once it is not present in the run-pool.
* Since the waitq is only set under @lock,
* the waiter should also briefly obtain and drop
* @lock to guarantee that the setter has completed
* its work on the kbase_context
* @job_done_wq: Workqueue to which the per atom work item is
* queued for bottom half processing when the
* atom completes
* execution on GPU or the input fence get signaled.
* @tb_lock: Lock to serialize the write access made to @tb to
* to store the register access trace messages.
* @tb: Pointer to the Userspace accessible buffer storing
* the trace messages for register read/write
* accesses made by the Kbase. The buffer is filled
* in circular fashion.
* @tb_wrap_offset: Offset to the end location in the trace buffer,
* the write pointer is moved to the beginning on
* reaching this offset.
* @work_id: atomic variable used for GPU tracepoints,
* incremented on every call to base_jd_submit.
* @jit_atoms_head: A list of the just-in-time memory soft-jobs, both
* allocate & free, in submission order, protected
* by kbase_jd_context.lock.
* @jit_pending_alloc: A list of just-in-time memory allocation
* soft-jobs which will be reattempted after the
* impending free of other active allocations.
*/
struct kbase_jd_context {
struct mutex lock;
struct kbasep_js_kctx_info sched_info;
struct kbase_jd_atom atoms[BASE_JD_ATOM_COUNT];
struct kbase_jd_renderpass renderpasses[BASE_JD_RP_COUNT];
struct workqueue_struct *job_done_wq;
wait_queue_head_t zero_jobs_wait;
spinlock_t tb_lock;
u32 *tb;
u32 job_nr;
size_t tb_wrap_offset;
#ifdef CONFIG_GPU_TRACEPOINTS
atomic_t work_id;
#endif
struct list_head jit_atoms_head;
struct list_head jit_pending_alloc;
};
/**
* struct jsctx_queue - JS context atom queue
* @runnable_tree: Root of RB-tree containing currently runnable atoms on this
* job slot.
* @x_dep_head: Head item of the linked list of atoms blocked on cross-slot
* dependencies. Atoms on this list will be moved to the
* runnable_tree when the blocking atom completes.
*
* hwaccess_lock must be held when accessing this structure.
*/
struct jsctx_queue {
struct rb_root runnable_tree;
struct list_head x_dep_head;
};
#endif /* _KBASE_JM_DEFS_H_ */

View File

@ -0,0 +1,136 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_JM_IOCTL_H_
#define _KBASE_JM_IOCTL_H_
#include <asm-generic/ioctl.h>
#include <linux/types.h>
/*
* 11.1:
* - Add BASE_MEM_TILER_ALIGN_TOP under base_mem_alloc_flags
* 11.2:
* - KBASE_MEM_QUERY_FLAGS can return KBASE_REG_PF_GROW and KBASE_REG_PROTECTED,
* which some user-side clients prior to 11.2 might fault if they received
* them
* 11.3:
* - New ioctls KBASE_IOCTL_STICKY_RESOURCE_MAP and
* KBASE_IOCTL_STICKY_RESOURCE_UNMAP
* 11.4:
* - New ioctl KBASE_IOCTL_MEM_FIND_GPU_START_AND_OFFSET
* 11.5:
* - New ioctl: KBASE_IOCTL_MEM_JIT_INIT (old ioctl renamed to _OLD)
* 11.6:
* - Added flags field to base_jit_alloc_info structure, which can be used to
* specify pseudo chunked tiler alignment for JIT allocations.
* 11.7:
* - Removed UMP support
* 11.8:
* - Added BASE_MEM_UNCACHED_GPU under base_mem_alloc_flags
* 11.9:
* - Added BASE_MEM_PERMANENT_KERNEL_MAPPING and BASE_MEM_FLAGS_KERNEL_ONLY
* under base_mem_alloc_flags
* 11.10:
* - Enabled the use of nr_extres field of base_jd_atom_v2 structure for
* JIT_ALLOC and JIT_FREE type softjobs to enable multiple JIT allocations
* with one softjob.
* 11.11:
* - Added BASE_MEM_GPU_VA_SAME_4GB_PAGE under base_mem_alloc_flags
* 11.12:
* - Removed ioctl: KBASE_IOCTL_GET_PROFILING_CONTROLS
* 11.13:
* - New ioctl: KBASE_IOCTL_MEM_EXEC_INIT
* 11.14:
* - Add BASE_MEM_GROUP_ID_MASK, base_mem_group_id_get, base_mem_group_id_set
* under base_mem_alloc_flags
* 11.15:
* - Added BASEP_CONTEXT_MMU_GROUP_ID_MASK under base_context_create_flags.
* - Require KBASE_IOCTL_SET_FLAGS before BASE_MEM_MAP_TRACKING_HANDLE can be
* passed to mmap().
* 11.16:
* - Extended ioctl KBASE_IOCTL_MEM_SYNC to accept imported dma-buf.
* - Modified (backwards compatible) ioctl KBASE_IOCTL_MEM_IMPORT behavior for
* dma-buf. Now, buffers are mapped on GPU when first imported, no longer
* requiring external resource or sticky resource tracking. UNLESS,
* CONFIG_MALI_DMA_BUF_MAP_ON_DEMAND is enabled.
* 11.17:
* - Added BASE_JD_REQ_JOB_SLOT.
* - Reused padding field in base_jd_atom_v2 to pass job slot number.
* - New ioctl: KBASE_IOCTL_GET_CPU_GPU_TIMEINFO
* 11.18:
* - Added BASE_MEM_IMPORT_SYNC_ON_MAP_UNMAP under base_mem_alloc_flags
* 11.19:
* - Extended base_jd_atom_v2 to allow a renderpass ID to be specified.
* 11.20:
* - Added new phys_pages member to kbase_ioctl_mem_jit_init for
* KBASE_IOCTL_MEM_JIT_INIT, previous variants of this renamed to use _10_2
* (replacing '_OLD') and _11_5 suffixes
* - Replaced compat_core_req (deprecated in 10.3) with jit_id[2] in
* base_jd_atom_v2. It must currently be initialized to zero.
* - Added heap_info_gpu_addr to base_jit_alloc_info, and
* BASE_JIT_ALLOC_HEAP_INFO_IS_SIZE allowable in base_jit_alloc_info's
* flags member. Previous variants of this structure are kept and given _10_2
* and _11_5 suffixes.
* - The above changes are checked for safe values in usual builds
* 11.21:
* - v2.0 of mali_trace debugfs file, which now versions the file separately
*/
#define BASE_UK_VERSION_MAJOR 11
#define BASE_UK_VERSION_MINOR 21
/**
* struct kbase_ioctl_job_submit - Submit jobs/atoms to the kernel
*
* @addr: Memory address of an array of struct base_jd_atom_v2
* @nr_atoms: Number of entries in the array
* @stride: sizeof(struct base_jd_atom_v2)
*/
struct kbase_ioctl_job_submit {
__u64 addr;
__u32 nr_atoms;
__u32 stride;
};
#define KBASE_IOCTL_JOB_SUBMIT \
_IOW(KBASE_IOCTL_TYPE, 2, struct kbase_ioctl_job_submit)
#define KBASE_IOCTL_POST_TERM \
_IO(KBASE_IOCTL_TYPE, 4)
/**
* struct kbase_ioctl_soft_event_update - Update the status of a soft-event
* @event: GPU address of the event which has been updated
* @new_status: The new status to set
* @flags: Flags for future expansion
*/
struct kbase_ioctl_soft_event_update {
__u64 event;
__u32 new_status;
__u32 flags;
};
#define KBASE_IOCTL_SOFT_EVENT_UPDATE \
_IOW(KBASE_IOCTL_TYPE, 28, struct kbase_ioctl_soft_event_update)
#endif /* _KBASE_JM_IOCTL_H_ */

View File

@ -0,0 +1,892 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Job Scheduler Interface.
* These interfaces are Internal to KBase.
*/
#ifndef _KBASE_JM_JS_H_
#define _KBASE_JM_JS_H_
#include "mali_kbase_js_ctx_attr.h"
/**
* kbasep_js_devdata_init - Initialize the Job Scheduler
*
* The struct kbasep_js_device_data sub-structure of kbdev must be zero
* initialized before passing to the kbasep_js_devdata_init() function. This is
* to give efficient error path code.
*/
int kbasep_js_devdata_init(struct kbase_device * const kbdev);
/**
* kbasep_js_devdata_halt - Halt the Job Scheduler.
*
* It is safe to call this on kbdev even if it the kbasep_js_device_data
* sub-structure was never initialized/failed initialization, to give efficient
* error-path code.
*
* For this to work, the struct kbasep_js_device_data sub-structure of kbdev
* must be zero initialized before passing to the kbasep_js_devdata_init()
* function. This is to give efficient error path code.
*
* It is a programming error to call this whilst there are still kbase_context
* structures registered with this scheduler.
*
*/
void kbasep_js_devdata_halt(struct kbase_device *kbdev);
/**
* kbasep_js_devdata_term - Terminate the Job Scheduler
*
* It is safe to call this on kbdev even if it the kbasep_js_device_data
* sub-structure was never initialized/failed initialization, to give efficient
* error-path code.
*
* For this to work, the struct kbasep_js_device_data sub-structure of kbdev
* must be zero initialized before passing to the kbasep_js_devdata_init()
* function. This is to give efficient error path code.
*
* It is a programming error to call this whilst there are still kbase_context
* structures registered with this scheduler.
*/
void kbasep_js_devdata_term(struct kbase_device *kbdev);
/**
* kbasep_js_kctx_init - Initialize the Scheduling Component of a
* struct kbase_context on the Job Scheduler.
*
* This effectively registers a struct kbase_context with a Job Scheduler.
*
* It does not register any jobs owned by the struct kbase_context with
* the scheduler. Those must be separately registered by kbasep_js_add_job().
*
* The struct kbase_context must be zero initialized before passing to the
* kbase_js_init() function. This is to give efficient error path code.
*/
int kbasep_js_kctx_init(struct kbase_context *const kctx);
/**
* kbasep_js_kctx_term - Terminate the Scheduling Component of a
* struct kbase_context on the Job Scheduler
*
* This effectively de-registers a struct kbase_context from its Job Scheduler
*
* It is safe to call this on a struct kbase_context that has never had or
* failed initialization of its jctx.sched_info member, to give efficient
* error-path code.
*
* For this to work, the struct kbase_context must be zero intitialized before
* passing to the kbase_js_init() function.
*
* It is a Programming Error to call this whilst there are still jobs
* registered with this context.
*/
void kbasep_js_kctx_term(struct kbase_context *kctx);
/**
* kbasep_js_add_job - Add a job chain to the Job Scheduler,
* and take necessary actions to
* schedule the context/run the job.
*
* This atomically does the following:
* * Update the numbers of jobs information
* * Add the job to the run pool if necessary (part of init_job)
*
* Once this is done, then an appropriate action is taken:
* * If the ctx is scheduled, it attempts to start the next job (which might be
* this added job)
* * Otherwise, and if this is the first job on the context, it enqueues it on
* the Policy Queue
*
* The Policy's Queue can be updated by this in the following ways:
* * In the above case that this is the first job on the context
* * If the context is high priority and the context is not scheduled, then it
* could cause the Policy to schedule out a low-priority context, allowing
* this context to be scheduled in.
*
* If the context is already scheduled on the RunPool, then adding a job to it
* is guaranteed not to update the Policy Queue. And so, the caller is
* guaranteed to not need to try scheduling a context from the Run Pool - it
* can safely assert that the result is false.
*
* It is a programming error to have more than U32_MAX jobs in flight at a time.
*
* The following locking conditions are made on the caller:
* * it must not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
* * it must not hold hwaccess_lock (as this will be obtained internally)
* * it must not hold kbasep_js_device_data::runpool_mutex (as this will be
* obtained internally)
* * it must not hold kbasep_jd_device_data::queue_mutex (again, it's used
* internally).
*
* Return: true indicates that the Policy Queue was updated, and so the
* caller will need to try scheduling a context onto the Run Pool,
* false indicates that no updates were made to the Policy Queue,
* so no further action is required from the caller. This is always returned
* when the context is currently scheduled.
*/
bool kbasep_js_add_job(struct kbase_context *kctx, struct kbase_jd_atom *atom);
/**
* kbasep_js_remove_job - Remove a job chain from the Job Scheduler,
* except for its 'retained state'.
*
* Completely removing a job requires several calls:
* * kbasep_js_copy_atom_retained_state(), to capture the 'retained state' of
* the atom
* * kbasep_js_remove_job(), to partially remove the atom from the Job Scheduler
* * kbasep_js_runpool_release_ctx_and_katom_retained_state(), to release the
* remaining state held as part of the job having been run.
*
* In the common case of atoms completing normally, this set of actions is more
* optimal for spinlock purposes than having kbasep_js_remove_job() handle all
* of the actions.
*
* In the case of canceling atoms, it is easier to call
* kbasep_js_remove_cancelled_job(), which handles all the necessary actions.
*
* It is a programming error to call this when:
* * a atom is not a job belonging to kctx.
* * a atom has already been removed from the Job Scheduler.
* * a atom is still in the runpool
*
* Do not use this for removing jobs being killed by kbase_jd_cancel() - use
* kbasep_js_remove_cancelled_job() instead.
*
* The following locking conditions are made on the caller:
* * it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
*
*/
void kbasep_js_remove_job(struct kbase_device *kbdev,
struct kbase_context *kctx, struct kbase_jd_atom *atom);
/**
* kbasep_js_remove_cancelled_job - Completely remove a job chain from the
* Job Scheduler, in the case
* where the job chain was cancelled.
*
* This is a variant of kbasep_js_remove_job() that takes care of removing all
* of the retained state too. This is generally useful for cancelled atoms,
* which need not be handled in an optimal way.
*
* It is a programming error to call this when:
* * a atom is not a job belonging to kctx.
* * a atom has already been removed from the Job Scheduler.
* * a atom is still in the runpool:
* * it is not being killed with kbasep_jd_cancel()
*
* The following locking conditions are made on the caller:
* * it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
* * it must not hold the hwaccess_lock, (as this will be obtained
* internally)
* * it must not hold kbasep_js_device_data::runpool_mutex (as this could be
* obtained internally)
*
* Return: true indicates that ctx attributes have changed and the caller
* should call kbase_js_sched_all() to try to run more jobs and
* false otherwise.
*/
bool kbasep_js_remove_cancelled_job(struct kbase_device *kbdev,
struct kbase_context *kctx,
struct kbase_jd_atom *katom);
/**
* kbasep_js_runpool_requeue_or_kill_ctx - Handling the requeuing/killing of a
* context that was evicted from the
* policy queue or runpool.
*
* This should be used whenever handing off a context that has been evicted
* from the policy queue or the runpool:
* * If the context is not dying and has jobs, it gets re-added to the policy
* queue
* * Otherwise, it is not added
*
* In addition, if the context is dying the jobs are killed asynchronously.
*
* In all cases, the Power Manager active reference is released
* (kbase_pm_context_idle()) whenever the has_pm_ref parameter is true.
* has_pm_ref must be set to false whenever the context was not previously in
* the runpool and does not hold a Power Manager active refcount. Note that
* contexts in a rollback of kbasep_js_try_schedule_head_ctx() might have an
* active refcount even though they weren't in the runpool.
*
* The following locking conditions are made on the caller:
* * it must hold kbasep_js_kctx_info::ctx::jsctx_mutex.
* * it must not hold kbasep_jd_device_data::queue_mutex (as this will be
* obtained internally)
*/
void kbasep_js_runpool_requeue_or_kill_ctx(struct kbase_device *kbdev,
struct kbase_context *kctx, bool has_pm_ref);
/**
* kbasep_js_runpool_release_ctx - Release a refcount of a context being busy,
* allowing it to be scheduled out.
*
* When the refcount reaches zero and the context might be scheduled out
* (depending on whether the Scheduling Policy has deemed it so, or if it has
* run out of jobs).
*
* If the context does get scheduled out, then The following actions will be
* taken as part of deschduling a context:
* For the context being descheduled:
* * If the context is in the processing of dying (all the jobs are being
* removed from it), then descheduling also kills off any jobs remaining in the
* context.
* * If the context is not dying, and any jobs remain after descheduling the
* context then it is re-enqueued to the Policy's Queue.
* * Otherwise, the context is still known to the scheduler, but remains absent
* from the Policy Queue until a job is next added to it.
* * In all descheduling cases, the Power Manager active reference (obtained
* during kbasep_js_try_schedule_head_ctx()) is released
* (kbase_pm_context_idle()).
*
* Whilst the context is being descheduled, this also handles actions that
* cause more atoms to be run:
* * Attempt submitting atoms when the Context Attributes on the Runpool have
* changed. This is because the context being scheduled out could mean that
* there are more opportunities to run atoms.
* * Attempt submitting to a slot that was previously blocked due to affinity
* restrictions. This is usually only necessary when releasing a context
* happens as part of completing a previous job, but is harmless nonetheless.
* * Attempt scheduling in a new context (if one is available), and if
* necessary, running a job from that new context.
*
* Unlike retaining a context in the runpool, this function cannot be called
* from IRQ context.
*
* It is a programming error to call this on a kctx that is not currently
* scheduled, or that already has a zero refcount.
*
* The following locking conditions are made on the caller:
* * it must not hold the hwaccess_lock, because it will be used internally.
* * it must not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
* * it must not hold kbasep_js_device_data::runpool_mutex (as this will be
* obtained internally)
* * it must not hold the kbase_device::mmu_hw_mutex (as this will be
* obtained internally)
* * it must not hold kbasep_jd_device_data::queue_mutex (as this will be
* obtained internally)
*
*/
void kbasep_js_runpool_release_ctx(struct kbase_device *kbdev,
struct kbase_context *kctx);
/**
* kbasep_js_runpool_release_ctx_and_katom_retained_state - Variant of
* kbasep_js_runpool_release_ctx() that handles additional
* actions from completing an atom.
*
* This is usually called as part of completing an atom and releasing the
* refcount on the context held by the atom.
*
* Therefore, the extra actions carried out are part of handling actions queued
* on a completed atom, namely:
* * Releasing the atom's context attributes
* * Retrying the submission on a particular slot, because we couldn't submit
* on that slot from an IRQ handler.
*
* The locking conditions of this function are the same as those for
* kbasep_js_runpool_release_ctx()
*/
void kbasep_js_runpool_release_ctx_and_katom_retained_state(
struct kbase_device *kbdev,
struct kbase_context *kctx,
struct kbasep_js_atom_retained_state *katom_retained_state);
/**
* kbasep_js_runpool_release_ctx_nolock - Variant of
* kbase_js_runpool_release_ctx() that assumes that
* kbasep_js_device_data::runpool_mutex and
* kbasep_js_kctx_info::ctx::jsctx_mutex are held by the caller, and does not
* attempt to schedule new contexts.
*/
void kbasep_js_runpool_release_ctx_nolock(struct kbase_device *kbdev,
struct kbase_context *kctx);
/**
* kbasep_js_schedule_privileged_ctx - Schedule in a privileged context
*
* This schedules a context in regardless of the context priority.
* If the runpool is full, a context will be forced out of the runpool and the
* function will wait for the new context to be scheduled in.
* The context will be kept scheduled in (and the corresponding address space
* reserved) until kbasep_js_release_privileged_ctx is called).
*
* The following locking conditions are made on the caller:
* * it must not hold the hwaccess_lock, because it will be used internally.
* * it must not hold kbasep_js_device_data::runpool_mutex (as this will be
* obtained internally)
* * it must not hold the kbase_device::mmu_hw_mutex (as this will be
* obtained internally)
* * it must not hold kbasep_jd_device_data::queue_mutex (again, it's used
* internally).
* * it must not hold kbasep_js_kctx_info::ctx::jsctx_mutex, because it will
* be used internally.
*
*/
void kbasep_js_schedule_privileged_ctx(struct kbase_device *kbdev,
struct kbase_context *kctx);
/**
* kbasep_js_release_privileged_ctx - Release a privileged context,
* allowing it to be scheduled out.
*
* See kbasep_js_runpool_release_ctx for potential side effects.
*
* The following locking conditions are made on the caller:
* * it must not hold the hwaccess_lock, because it will be used internally.
* * it must not hold kbasep_js_kctx_info::ctx::jsctx_mutex.
* * it must not hold kbasep_js_device_data::runpool_mutex (as this will be
* obtained internally)
* * it must not hold the kbase_device::mmu_hw_mutex (as this will be
* obtained internally)
*
*/
void kbasep_js_release_privileged_ctx(struct kbase_device *kbdev,
struct kbase_context *kctx);
/**
* kbase_js_try_run_jobs - Try to submit the next job on each slot
*
* The following locks may be used:
* * kbasep_js_device_data::runpool_mutex
* * hwaccess_lock
*/
void kbase_js_try_run_jobs(struct kbase_device *kbdev);
/**
* kbasep_js_suspend - Suspend the job scheduler during a Power Management
* Suspend event.
*
* Causes all contexts to be removed from the runpool, and prevents any
* contexts from (re)entering the runpool.
*
* This does not handle suspending the one privileged context: the caller must
* instead do this by by suspending the GPU HW Counter Instrumentation.
*
* This will eventually cause all Power Management active references held by
* contexts on the runpool to be released, without running any more atoms.
*
* The caller must then wait for all Power Management active refcount to become
* zero before completing the suspend.
*
* The emptying mechanism may take some time to complete, since it can wait for
* jobs to complete naturally instead of forcing them to end quickly. However,
* this is bounded by the Job Scheduler's Job Timeouts. Hence, this
* function is guaranteed to complete in a finite time.
*/
void kbasep_js_suspend(struct kbase_device *kbdev);
/**
* kbasep_js_resume - Resume the Job Scheduler after a Power Management
* Resume event.
*
* This restores the actions from kbasep_js_suspend():
* * Schedules contexts back into the runpool
* * Resumes running atoms on the GPU
*/
void kbasep_js_resume(struct kbase_device *kbdev);
/**
* kbase_js_dep_resolved_submit - Submit an atom to the job scheduler.
*
* @kctx: Context pointer
* @atom: Pointer to the atom to submit
*
* The atom is enqueued on the context's ringbuffer. The caller must have
* ensured that all dependencies can be represented in the ringbuffer.
*
* Caller must hold jctx->lock
*
* Return: true if the context requires to be enqueued, otherwise false.
*/
bool kbase_js_dep_resolved_submit(struct kbase_context *kctx,
struct kbase_jd_atom *katom);
/**
* jsctx_ll_flush_to_rb() - Pushes atoms from the linked list to ringbuffer.
* @kctx: Context Pointer
* @prio: Priority (specifies the queue together with js).
* @js: Job slot (specifies the queue together with prio).
*
* Pushes all possible atoms from the linked list to the ringbuffer.
* Number of atoms are limited to free space in the ringbuffer and
* number of available atoms in the linked list.
*
*/
void jsctx_ll_flush_to_rb(struct kbase_context *kctx, int prio, int js);
/**
* kbase_js_pull - Pull an atom from a context in the job scheduler for
* execution.
*
* @kctx: Context to pull from
* @js: Job slot to pull from
*
* The atom will not be removed from the ringbuffer at this stage.
*
* The HW access lock must be held when calling this function.
*
* Return: a pointer to an atom, or NULL if there are no atoms for this
* slot that can be currently run.
*/
struct kbase_jd_atom *kbase_js_pull(struct kbase_context *kctx, int js);
/**
* kbase_js_unpull - Return an atom to the job scheduler ringbuffer.
*
* @kctx: Context pointer
* @atom: Pointer to the atom to unpull
*
* An atom is 'unpulled' if execution is stopped but intended to be returned to
* later. The most common reason for this is that the atom has been
* soft-stopped. Another reason is if an end-of-renderpass atom completed
* but will need to be run again as part of the same renderpass.
*
* Note that if multiple atoms are to be 'unpulled', they must be returned in
* the reverse order to which they were originally pulled. It is a programming
* error to return atoms in any other order.
*
* The HW access lock must be held when calling this function.
*
*/
void kbase_js_unpull(struct kbase_context *kctx, struct kbase_jd_atom *katom);
/**
* kbase_js_complete_atom_wq - Complete an atom from jd_done_worker(),
* removing it from the job
* scheduler ringbuffer.
* @kctx: Context pointer
* @katom: Pointer to the atom to complete
*
* If the atom failed then all dependee atoms marked for failure propagation
* will also fail.
*
* Return: true if the context is now idle (no jobs pulled) false otherwise.
*/
bool kbase_js_complete_atom_wq(struct kbase_context *kctx,
struct kbase_jd_atom *katom);
/**
* kbase_js_complete_atom - Complete an atom.
*
* @katom: Pointer to the atom to complete
* @end_timestamp: The time that the atom completed (may be NULL)
*
* Most of the work required to complete an atom will be performed by
* jd_done_worker().
*
* The HW access lock must be held when calling this function.
*
* Return: a atom that has now been unblocked and can now be run, or NULL
* if none
*/
struct kbase_jd_atom *kbase_js_complete_atom(struct kbase_jd_atom *katom,
ktime_t *end_timestamp);
/**
* kbase_js_atom_blocked_on_x_dep - Decide whether to ignore a cross-slot
* dependency
* @katom: Pointer to an atom in the slot ringbuffer
*
* A cross-slot dependency is ignored if necessary to unblock incremental
* rendering. If the atom at the start of a renderpass used too much memory
* and was soft-stopped then the atom at the end of a renderpass is submitted
* to hardware regardless of its dependency on the start-of-renderpass atom.
* This can happen multiple times for the same pair of atoms.
*
* Return: true to block the atom or false to allow it to be submitted to
* hardware.
*/
bool kbase_js_atom_blocked_on_x_dep(struct kbase_jd_atom *katom);
/**
* kbase_js_sched - Submit atoms from all available contexts.
*
* @kbdev: Device pointer
* @js_mask: Mask of job slots to submit to
*
* This will attempt to submit as many jobs as possible to the provided job
* slots. It will exit when either all job slots are full, or all contexts have
* been used.
*
*/
void kbase_js_sched(struct kbase_device *kbdev, int js_mask);
/**
* kbase_jd_zap_context - Attempt to deschedule a context that is being
* destroyed
* @kctx: Context pointer
*
* This will attempt to remove a context from any internal job scheduler queues
* and perform any other actions to ensure a context will not be submitted
* from.
*
* If the context is currently scheduled, then the caller must wait for all
* pending jobs to complete before taking any further action.
*/
void kbase_js_zap_context(struct kbase_context *kctx);
/**
* kbase_js_is_atom_valid - Validate an atom
*
* @kbdev: Device pointer
* @katom: Atom to validate
*
* This will determine whether the atom can be scheduled onto the GPU. Atoms
* with invalid combinations of core requirements will be rejected.
*
* Return: true if atom is valid false otherwise.
*/
bool kbase_js_is_atom_valid(struct kbase_device *kbdev,
struct kbase_jd_atom *katom);
/**
* kbase_js_set_timeouts - update all JS timeouts with user specified data
*
* @kbdev: Device pointer
*
* Timeouts are specified through the 'js_timeouts' sysfs file. If a timeout is
* set to a positive number then that becomes the new value used, if a timeout
* is negative then the default is set.
*/
void kbase_js_set_timeouts(struct kbase_device *kbdev);
/**
* kbase_js_set_ctx_priority - set the context priority
*
* @kctx: Context pointer
* @new_priority: New priority value for the Context
*
* The context priority is set to a new value and it is moved to the
* pullable/unpullable list as per the new priority.
*/
void kbase_js_set_ctx_priority(struct kbase_context *kctx, int new_priority);
/**
* kbase_js_update_ctx_priority - update the context priority
*
* @kctx: Context pointer
*
* The context priority gets updated as per the priority of atoms currently in
* use for that context, but only if system priority mode for context scheduling
* is being used.
*/
void kbase_js_update_ctx_priority(struct kbase_context *kctx);
/*
* Helpers follow
*/
/**
* kbasep_js_is_submit_allowed - Check that a context is allowed to submit
* jobs on this policy
*
* The purpose of this abstraction is to hide the underlying data size,
* and wrap up the long repeated line of code.
*
* As with any bool, never test the return value with true.
*
* The caller must hold hwaccess_lock.
*/
static inline bool kbasep_js_is_submit_allowed(
struct kbasep_js_device_data *js_devdata,
struct kbase_context *kctx)
{
u16 test_bit;
bool is_allowed;
/* Ensure context really is scheduled in */
KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
test_bit = (u16) (1u << kctx->as_nr);
is_allowed = (bool) (js_devdata->runpool_irq.submit_allowed & test_bit);
dev_dbg(kctx->kbdev->dev, "JS: submit %s allowed on %p (as=%d)",
is_allowed ? "is" : "isn't", (void *)kctx, kctx->as_nr);
return is_allowed;
}
/**
* kbasep_js_set_submit_allowed - Allow a context to submit jobs on this policy
*
* The purpose of this abstraction is to hide the underlying data size,
* and wrap up the long repeated line of code.
*
* The caller must hold hwaccess_lock.
*/
static inline void kbasep_js_set_submit_allowed(
struct kbasep_js_device_data *js_devdata,
struct kbase_context *kctx)
{
u16 set_bit;
/* Ensure context really is scheduled in */
KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
set_bit = (u16) (1u << kctx->as_nr);
dev_dbg(kctx->kbdev->dev, "JS: Setting Submit Allowed on %p (as=%d)",
kctx, kctx->as_nr);
js_devdata->runpool_irq.submit_allowed |= set_bit;
}
/**
* kbasep_js_clear_submit_allowed - Prevent a context from submitting more
* jobs on this policy
*
* The purpose of this abstraction is to hide the underlying data size,
* and wrap up the long repeated line of code.
*
* The caller must hold hwaccess_lock.
*/
static inline void kbasep_js_clear_submit_allowed(
struct kbasep_js_device_data *js_devdata,
struct kbase_context *kctx)
{
u16 clear_bit;
u16 clear_mask;
/* Ensure context really is scheduled in */
KBASE_DEBUG_ASSERT(kctx->as_nr != KBASEP_AS_NR_INVALID);
KBASE_DEBUG_ASSERT(kbase_ctx_flag(kctx, KCTX_SCHEDULED));
clear_bit = (u16) (1u << kctx->as_nr);
clear_mask = ~clear_bit;
dev_dbg(kctx->kbdev->dev, "JS: Clearing Submit Allowed on %p (as=%d)",
kctx, kctx->as_nr);
js_devdata->runpool_irq.submit_allowed &= clear_mask;
}
/**
* Create an initial 'invalid' atom retained state, that requires no
* atom-related work to be done on releasing with
* kbasep_js_runpool_release_ctx_and_katom_retained_state()
*/
static inline void kbasep_js_atom_retained_state_init_invalid(
struct kbasep_js_atom_retained_state *retained_state)
{
retained_state->event_code = BASE_JD_EVENT_NOT_STARTED;
retained_state->core_req =
KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID;
}
/**
* Copy atom state that can be made available after jd_done_nolock() is called
* on that atom.
*/
static inline void kbasep_js_atom_retained_state_copy(
struct kbasep_js_atom_retained_state *retained_state,
const struct kbase_jd_atom *katom)
{
retained_state->event_code = katom->event_code;
retained_state->core_req = katom->core_req;
retained_state->sched_priority = katom->sched_priority;
retained_state->device_nr = katom->device_nr;
}
/**
* kbasep_js_has_atom_finished - Determine whether an atom has finished
* (given its retained state),
* and so should be given back to
* userspace/removed from the system.
*
* @katom_retained_state: the retained state of the atom to check
*
* Reasons for an atom not finishing include:
* * Being soft-stopped (and so, the atom should be resubmitted sometime later)
* * It is an end of renderpass atom that was run to consume the output of a
* start-of-renderpass atom that was soft-stopped because it used too much
* memory. In this case, it will have to be run again later.
*
* Return: false if the atom has not finished, true otherwise.
*/
static inline bool kbasep_js_has_atom_finished(
const struct kbasep_js_atom_retained_state *katom_retained_state)
{
return (bool) (katom_retained_state->event_code !=
BASE_JD_EVENT_STOPPED &&
katom_retained_state->event_code !=
BASE_JD_EVENT_REMOVED_FROM_NEXT &&
katom_retained_state->event_code !=
BASE_JD_EVENT_END_RP_DONE);
}
/**
* kbasep_js_atom_retained_state_is_valid - Determine whether a struct
* kbasep_js_atom_retained_state
* is valid
* @katom_retained_state the atom's retained state to check
*
* An invalid struct kbasep_js_atom_retained_state is allowed, and indicates
* that the code should just ignore it.
*
* Return: false if the retained state is invalid, true otherwise.
*/
static inline bool kbasep_js_atom_retained_state_is_valid(
const struct kbasep_js_atom_retained_state *katom_retained_state)
{
return (bool) (katom_retained_state->core_req !=
KBASEP_JS_ATOM_RETAINED_STATE_CORE_REQ_INVALID);
}
/**
* kbase_js_runpool_inc_context_count - Increment number of running contexts.
*
* The following locking conditions are made on the caller:
* * The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex.
* * The caller must hold the kbasep_js_device_data::runpool_mutex
*/
static inline void kbase_js_runpool_inc_context_count(
struct kbase_device *kbdev,
struct kbase_context *kctx)
{
struct kbasep_js_device_data *js_devdata;
struct kbasep_js_kctx_info *js_kctx_info;
KBASE_DEBUG_ASSERT(kbdev != NULL);
KBASE_DEBUG_ASSERT(kctx != NULL);
js_devdata = &kbdev->js_data;
js_kctx_info = &kctx->jctx.sched_info;
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
lockdep_assert_held(&js_devdata->runpool_mutex);
/* Track total contexts */
KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running < S8_MAX);
++(js_devdata->nr_all_contexts_running);
if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) {
/* Track contexts that can submit jobs */
KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running <
S8_MAX);
++(js_devdata->nr_user_contexts_running);
}
}
/**
* kbase_js_runpool_dec_context_count - decrement number of running contexts.
*
* The following locking conditions are made on the caller:
* * The caller must hold the kbasep_js_kctx_info::ctx::jsctx_mutex.
* * The caller must hold the kbasep_js_device_data::runpool_mutex
*/
static inline void kbase_js_runpool_dec_context_count(
struct kbase_device *kbdev,
struct kbase_context *kctx)
{
struct kbasep_js_device_data *js_devdata;
struct kbasep_js_kctx_info *js_kctx_info;
KBASE_DEBUG_ASSERT(kbdev != NULL);
KBASE_DEBUG_ASSERT(kctx != NULL);
js_devdata = &kbdev->js_data;
js_kctx_info = &kctx->jctx.sched_info;
lockdep_assert_held(&js_kctx_info->ctx.jsctx_mutex);
lockdep_assert_held(&js_devdata->runpool_mutex);
/* Track total contexts */
--(js_devdata->nr_all_contexts_running);
KBASE_DEBUG_ASSERT(js_devdata->nr_all_contexts_running >= 0);
if (!kbase_ctx_flag(kctx, KCTX_SUBMIT_DISABLED)) {
/* Track contexts that can submit jobs */
--(js_devdata->nr_user_contexts_running);
KBASE_DEBUG_ASSERT(js_devdata->nr_user_contexts_running >= 0);
}
}
/**
* kbase_js_sched_all - Submit atoms from all available contexts to all
* job slots.
*
* @kbdev: Device pointer
*
* This will attempt to submit as many jobs as possible. It will exit when
* either all job slots are full, or all contexts have been used.
*/
static inline void kbase_js_sched_all(struct kbase_device *kbdev)
{
kbase_js_sched(kbdev, (1 << kbdev->gpu_props.num_job_slots) - 1);
}
extern const int
kbasep_js_atom_priority_to_relative[BASE_JD_NR_PRIO_LEVELS];
extern const base_jd_prio
kbasep_js_relative_priority_to_atom[KBASE_JS_ATOM_SCHED_PRIO_COUNT];
/**
* kbasep_js_atom_prio_to_sched_prio(): - Convert atom priority (base_jd_prio)
* to relative ordering
* @atom_prio: Priority ID to translate.
*
* Atom priority values for @ref base_jd_prio cannot be compared directly to
* find out which are higher or lower.
*
* This function will convert base_jd_prio values for successively lower
* priorities into a monotonically increasing sequence. That is, the lower the
* base_jd_prio priority, the higher the value produced by this function. This
* is in accordance with how the rest of the kernel treats priority.
*
* The mapping is 1:1 and the size of the valid input range is the same as the
* size of the valid output range, i.e.
* KBASE_JS_ATOM_SCHED_PRIO_COUNT == BASE_JD_NR_PRIO_LEVELS
*
* Note This must be kept in sync with BASE_JD_PRIO_<...> definitions
*
* Return: On success: a value in the inclusive range
* 0..KBASE_JS_ATOM_SCHED_PRIO_COUNT-1. On failure:
* KBASE_JS_ATOM_SCHED_PRIO_INVALID
*/
static inline int kbasep_js_atom_prio_to_sched_prio(base_jd_prio atom_prio)
{
if (atom_prio >= BASE_JD_NR_PRIO_LEVELS)
return KBASE_JS_ATOM_SCHED_PRIO_INVALID;
return kbasep_js_atom_priority_to_relative[atom_prio];
}
static inline base_jd_prio kbasep_js_sched_prio_to_atom_prio(int sched_prio)
{
unsigned int prio_idx;
KBASE_DEBUG_ASSERT(sched_prio >= 0 &&
sched_prio < KBASE_JS_ATOM_SCHED_PRIO_COUNT);
prio_idx = (unsigned int)sched_prio;
return kbasep_js_relative_priority_to_atom[prio_idx];
}
#endif /* _KBASE_JM_JS_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2018, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -21,7 +21,6 @@
*/
/**
* @file mali_kbase_js.h
* Job Scheduler Type Definitions
@ -51,12 +50,6 @@ struct kbase_jd_atom;
typedef u32 kbase_context_flags;
struct kbasep_atom_req {
base_jd_core_req core_req;
kbase_context_flags ctx_req;
u32 device_nr;
};
/** Callback function run on all of a context's jobs registered with the Job
* Scheduler */
typedef void (*kbasep_js_ctx_job_cb)(struct kbase_device *kbdev, struct kbase_jd_atom *katom);
@ -245,24 +238,6 @@ struct kbasep_js_device_data {
s8 slot_affinity_refcount[BASE_JM_MAX_NR_SLOTS][64];
} runpool_irq;
/**
* Run Pool mutex, for managing contexts within the runpool.
* Unless otherwise specified, you must hold this lock whilst accessing any
* members that follow
*
* In addition, this is used to access:
* - the kbasep_js_kctx_info::runpool substructure
*/
struct mutex runpool_mutex;
/**
* Queue Lock, used to access the Policy's queue of contexts independently
* of the Run Pool.
*
* Of course, you don't need the Run Pool lock to access this.
*/
struct mutex queue_mutex;
/**
* Scheduling semaphore. This must be held when calling
* kbase_jm_kick()
@ -299,9 +274,6 @@ struct kbasep_js_device_data {
u32 gpu_reset_ticks_dumping; /*< Value for JS_RESET_TICKS_DUMPING */
u32 ctx_timeslice_ns; /**< Value for JS_CTX_TIMESLICE_NS */
/**< Value for JS_SOFT_JOB_TIMEOUT */
atomic_t soft_job_timeout_ms;
/** List of suspended soft jobs */
struct list_head suspended_soft_jobs_list;
@ -321,6 +293,27 @@ struct kbasep_js_device_data {
/* Number of contexts that can either be pulled from or are currently
* running */
atomic_t nr_contexts_runnable;
/** Value for JS_SOFT_JOB_TIMEOUT */
atomic_t soft_job_timeout_ms;
/**
* Queue Lock, used to access the Policy's queue of contexts
* independently of the Run Pool.
*
* Of course, you don't need the Run Pool lock to access this.
*/
struct mutex queue_mutex;
/**
* Run Pool mutex, for managing contexts within the runpool.
* Unless otherwise specified, you must hold this lock whilst accessing
* any members that follow
*
* In addition, this is used to access:
* * the kbasep_js_kctx_info::runpool substructure
*/
struct mutex runpool_mutex;
};
/**

View File

@ -48,7 +48,6 @@ enum base_hw_feature {
BASE_HW_FEATURE_BRNDOUT_KILL,
BASE_HW_FEATURE_WARPING,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_AARCH64_MMU,
@ -85,7 +84,6 @@ static const enum base_hw_feature base_hw_features_tMIx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
BASE_HW_FEATURE_END
@ -112,7 +110,6 @@ static const enum base_hw_feature base_hw_features_tHEx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -140,7 +137,6 @@ static const enum base_hw_feature base_hw_features_tSIx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -168,7 +164,6 @@ static const enum base_hw_feature base_hw_features_tDVx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -196,7 +191,6 @@ static const enum base_hw_feature base_hw_features_tNOx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -226,7 +220,6 @@ static const enum base_hw_feature base_hw_features_tGOx[] = {
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_THREAD_GROUP_SPLIT,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -255,7 +248,6 @@ static const enum base_hw_feature base_hw_features_tTRx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -284,7 +276,6 @@ static const enum base_hw_feature base_hw_features_tNAx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -313,7 +304,6 @@ static const enum base_hw_feature base_hw_features_tBEx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -323,35 +313,6 @@ static const enum base_hw_feature base_hw_features_tBEx[] = {
BASE_HW_FEATURE_END
};
static const enum base_hw_feature base_hw_features_tULx[] = {
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
BASE_HW_FEATURE_XAFFINITY,
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,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
BASE_HW_FEATURE_L2_CONFIG,
BASE_HW_FEATURE_CLEAN_ONLY_SAFE,
BASE_HW_FEATURE_END
};
static const enum base_hw_feature base_hw_features_tDUx[] = {
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
@ -372,7 +333,6 @@ static const enum base_hw_feature base_hw_features_tDUx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -402,7 +362,6 @@ static const enum base_hw_feature base_hw_features_tODx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -411,7 +370,7 @@ static const enum base_hw_feature base_hw_features_tODx[] = {
BASE_HW_FEATURE_END
};
static const enum base_hw_feature base_hw_features_tIDx[] = {
static const enum base_hw_feature base_hw_features_tGRx[] = {
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
BASE_HW_FEATURE_XAFFINITY,
@ -431,7 +390,6 @@ static const enum base_hw_feature base_hw_features_tIDx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -460,7 +418,6 @@ static const enum base_hw_feature base_hw_features_tVAx[] = {
BASE_HW_FEATURE_T7XX_PAIRING_RULES,
BASE_HW_FEATURE_TEST4_DATUM_MODE,
BASE_HW_FEATURE_FLUSH_REDUCTION,
BASE_HW_FEATURE_PROTECTED_MODE,
BASE_HW_FEATURE_PROTECTED_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
@ -469,4 +426,61 @@ static const enum base_hw_feature base_hw_features_tVAx[] = {
BASE_HW_FEATURE_END
};
static const enum base_hw_feature base_hw_features_tTUx[] = {
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
BASE_HW_FEATURE_XAFFINITY,
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_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
BASE_HW_FEATURE_L2_CONFIG,
BASE_HW_FEATURE_CLEAN_ONLY_SAFE,
BASE_HW_FEATURE_END
};
static const enum base_hw_feature base_hw_features_tE2x[] = {
BASE_HW_FEATURE_JOBCHAIN_DISAMBIGUATION,
BASE_HW_FEATURE_PWRON_DURING_PWROFF_TRANS,
BASE_HW_FEATURE_XAFFINITY,
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_DEBUG_MODE,
BASE_HW_FEATURE_COHERENCY_REG,
BASE_HW_FEATURE_AARCH64_MMU,
BASE_HW_FEATURE_IDVS_GROUP_SIZE,
BASE_HW_FEATURE_L2_CONFIG,
BASE_HW_FEATURE_CLEAN_ONLY_SAFE,
BASE_HW_FEATURE_END
};
#endif /* _BASE_HWCONFIG_FEATURES_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -53,7 +53,12 @@ enum base_hw_issue {
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
@ -206,6 +211,7 @@ static const enum base_hw_issue base_hw_issues_tSIx_r0p0[] = {
BASE_HW_ISSUE_TSIX_1792,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -218,6 +224,7 @@ static const enum base_hw_issue base_hw_issues_tSIx_r0p1[] = {
BASE_HW_ISSUE_TSIX_1792,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -229,6 +236,7 @@ static const enum base_hw_issue base_hw_issues_tSIx_r1p0[] = {
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -239,6 +247,7 @@ static const enum base_hw_issue base_hw_issues_tSIx_r1p1[] = {
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -248,6 +257,7 @@ static const enum base_hw_issue base_hw_issues_model_tSIx[] = {
BASE_HW_ISSUE_TMIX_8133,
BASE_HW_ISSUE_TSIX_1116,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -258,6 +268,7 @@ static const enum base_hw_issue base_hw_issues_tDVx_r0p0[] = {
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -267,6 +278,7 @@ static const enum base_hw_issue base_hw_issues_model_tDVx[] = {
BASE_HW_ISSUE_TMIX_8133,
BASE_HW_ISSUE_TSIX_1116,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -278,6 +290,7 @@ static const enum base_hw_issue base_hw_issues_tNOx_r0p0[] = {
BASE_HW_ISSUE_TNOX_1194,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -287,6 +300,7 @@ static const enum base_hw_issue base_hw_issues_model_tNOx[] = {
BASE_HW_ISSUE_TMIX_8133,
BASE_HW_ISSUE_TSIX_1116,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -298,6 +312,7 @@ static const enum base_hw_issue base_hw_issues_tGOx_r0p0[] = {
BASE_HW_ISSUE_TNOX_1194,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -309,6 +324,7 @@ static const enum base_hw_issue base_hw_issues_tGOx_r1p0[] = {
BASE_HW_ISSUE_TGOX_R1_1234,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -318,6 +334,7 @@ static const enum base_hw_issue base_hw_issues_model_tGOx[] = {
BASE_HW_ISSUE_TMIX_8133,
BASE_HW_ISSUE_TSIX_1116,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -328,7 +345,12 @@ static const enum base_hw_issue base_hw_issues_tTRx_r0p0[] = {
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
@ -339,7 +361,27 @@ static const enum base_hw_issue base_hw_issues_tTRx_r0p1[] = {
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tTRx_r0p2[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -348,6 +390,10 @@ static const enum base_hw_issue base_hw_issues_model_tTRx[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -358,7 +404,12 @@ static const enum base_hw_issue base_hw_issues_tNAx_r0p0[] = {
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
@ -369,7 +420,11 @@ static const enum base_hw_issue base_hw_issues_tNAx_r0p1[] = {
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_3076,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_GPU2017_1336,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -378,6 +433,10 @@ static const enum base_hw_issue base_hw_issues_model_tNAx[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -387,6 +446,24 @@ static const enum base_hw_issue base_hw_issues_tBEx_r0p0[] = {
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tBEx_r0p1[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -396,6 +473,23 @@ static const enum base_hw_issue base_hw_issues_tBEx_r1p0[] = {
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tBEx_r1p1[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -404,22 +498,37 @@ static const enum base_hw_issue base_hw_issues_model_tBEx[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tULx_r0p0[] = {
static const enum base_hw_issue base_hw_issues_lBEx_r1p0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_TTRX_3485,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_model_tULx[] = {
BASE_HW_ISSUE_5736,
static const enum base_hw_issue base_hw_issues_lBEx_r1p1[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_2968_TTRX_3162,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_TTRX_3470,
BASE_HW_ISSUE_TTRX_3464,
BASE_HW_ISSUE_END
};
@ -428,6 +537,8 @@ static const enum base_hw_issue base_hw_issues_tDUx_r0p0[] = {
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_END
};
@ -436,6 +547,8 @@ static const enum base_hw_issue base_hw_issues_model_tDUx[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_END
};
@ -454,14 +567,14 @@ static const enum base_hw_issue base_hw_issues_model_tODx[] = {
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tIDx_r0p0[] = {
static const enum base_hw_issue base_hw_issues_tGRx_r0p0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_model_tIDx[] = {
static const enum base_hw_issue base_hw_issues_model_tGRx[] = {
BASE_HW_ISSUE_5736,
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
@ -484,4 +597,39 @@ static const enum base_hw_issue base_hw_issues_model_tVAx[] = {
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tTUx_r0p0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_model_tTUx[] = {
BASE_HW_ISSUE_5736,
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_tE2x_r0p0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_921,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_END
};
static const enum base_hw_issue base_hw_issues_model_tE2x[] = {
BASE_HW_ISSUE_5736,
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_TSIX_2033,
BASE_HW_ISSUE_TTRX_1337,
BASE_HW_ISSUE_TTRX_3414,
BASE_HW_ISSUE_TTRX_3083,
BASE_HW_ISSUE_END
};
#endif /* _BASE_HWCONFIG_ISSUES_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2014 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2015, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -47,7 +47,7 @@
* - offset is ignored.
*/
struct basep_syncset {
base_mem_handle mem_handle;
struct base_mem_handle mem_handle;
u64 user_addr;
u64 size;
u8 type;

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -56,19 +56,21 @@
*/
#include "mali_kbase_defs.h"
#include "mali_kbase_context.h"
#include "debug/mali_kbase_debug_ktrace.h"
#include "context/mali_kbase_context.h"
#include "mali_kbase_strings.h"
#include "mali_kbase_mem_lowlevel.h"
#include "mali_kbase_js.h"
#include "mali_kbase_utility.h"
#include "mali_kbase_mem.h"
#include "mmu/mali_kbase_mmu.h"
#include "mali_kbase_gpu_memory_debugfs.h"
#include "mali_kbase_mem_profile_debugfs.h"
#include "mali_kbase_gpuprops.h"
#include "mali_kbase_ioctl.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_ioctl.h"
#include "mali_kbase_js.h"
#include "ipa/mali_kbase_ipa.h"
@ -76,6 +78,8 @@
#include <trace/events/gpu.h>
#endif
#include "mali_linux_trace.h"
#ifndef u64_to_user_ptr
/* Introduced in Linux v4.6 */
@ -97,16 +101,8 @@ struct kbase_device *kbase_device_alloc(void);
* been setup before calling kbase_device_init
*/
/*
* API to acquire device list semaphore 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);
int kbase_device_misc_init(struct kbase_device *kbdev);
void kbase_device_misc_term(struct kbase_device *kbdev);
void kbase_device_free(struct kbase_device *kbdev);
int kbase_device_has_feature(struct kbase_device *kbdev, u32 feature);
@ -156,6 +152,60 @@ unsigned long kbase_context_get_unmapped_area(struct kbase_context *kctx,
const unsigned long addr, const unsigned long len,
const unsigned long pgoff, const unsigned long flags);
int assign_irqs(struct kbase_device *kbdev);
int kbase_sysfs_init(struct kbase_device *kbdev);
void kbase_sysfs_term(struct kbase_device *kbdev);
int kbase_protected_mode_init(struct kbase_device *kbdev);
void kbase_protected_mode_term(struct kbase_device *kbdev);
/**
* kbase_device_pm_init() - Performs power management initialization and
* Verifies device tree configurations.
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Return: 0 if successful, otherwise a standard Linux error code
*/
int kbase_device_pm_init(struct kbase_device *kbdev);
/**
* kbase_device_pm_term() - Performs power management deinitialization and
* Free resources.
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Clean up all the resources
*/
void kbase_device_pm_term(struct kbase_device *kbdev);
int power_control_init(struct kbase_device *kbdev);
void power_control_term(struct kbase_device *kbdev);
#ifdef CONFIG_DEBUG_FS
void kbase_device_debugfs_term(struct kbase_device *kbdev);
int kbase_device_debugfs_init(struct kbase_device *kbdev);
#else /* CONFIG_DEBUG_FS */
static inline int kbase_device_debugfs_init(struct kbase_device *kbdev)
{
return 0;
}
static inline void kbase_device_debugfs_term(struct kbase_device *kbdev) { }
#endif /* CONFIG_DEBUG_FS */
int registers_map(struct kbase_device *kbdev);
void registers_unmap(struct kbase_device *kbdev);
int kbase_device_coherency_init(struct kbase_device *kbdev);
#ifdef CONFIG_MALI_BUSLOG
int buslog_init(struct kbase_device *kbdev);
void buslog_term(struct kbase_device *kbdev);
#endif
int kbase_jd_init(struct kbase_context *kctx);
void kbase_jd_exit(struct kbase_context *kctx);
@ -200,9 +250,6 @@ 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_jd_dep_clear_locked(struct kbase_jd_atom *katom);
/**
@ -232,6 +279,22 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done);
void kbase_job_slot_ctx_priority_check_locked(struct kbase_context *kctx,
struct kbase_jd_atom *katom);
/**
* kbase_job_slot_softstop_start_rp() - Soft-stop the atom at the start
* of a renderpass.
* @kctx: Pointer to a kernel base context.
* @reg: Reference of a growable GPU memory region in the same context.
* Takes ownership of the reference if successful.
*
* Used to switch to incremental rendering if we have nearly run out of
* virtual address space in a growable memory region and the atom currently
* executing on a job slot is the tiler job chain at the start of a renderpass.
*
* Return 0 if successful, otherwise a negative error code.
*/
int kbase_job_slot_softstop_start_rp(struct kbase_context *kctx,
struct kbase_va_region *reg);
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,
@ -243,6 +306,7 @@ void kbase_job_check_enter_disjoint(struct kbase_device *kbdev, u32 action,
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);
@ -262,6 +326,16 @@ void kbase_event_wakeup(struct kbase_context *kctx);
*/
int kbasep_jit_alloc_validate(struct kbase_context *kctx,
struct base_jit_alloc_info *info);
/**
* kbase_jit_retry_pending_alloc() - Retry blocked just-in-time memory
* allocations.
*
* @kctx: Pointer to the kbase context within which the just-in-time
* memory allocations are to be retried.
*/
void kbase_jit_retry_pending_alloc(struct kbase_context *kctx);
/**
* kbase_free_user_buffer() - Free memory allocated for struct
* @kbase_debug_copy_buffer.
@ -288,23 +362,6 @@ static inline void kbase_free_user_buffer(
}
}
/**
* kbase_mem_copy_from_extres_page() - Copy pages from external resources.
*
* @kctx: kbase context within which the copying is to take place.
* @extres_pages: Pointer to the pages which correspond to the external
* resources from which the copying will take place.
* @pages: Pointer to the pages to which the content is to be
* copied from the provided external resources.
* @nr_pages: Number of pages to copy.
* @target_page_nr: Number of target pages which will be used for copying.
* @offset: Offset into the target pages from which the copying
* is to be performed.
* @to_copy: Size of the chunk to be copied, in bytes.
*/
void kbase_mem_copy_from_extres_page(struct kbase_context *kctx,
void *extres_page, struct page **pages, unsigned int nr_pages,
unsigned int *target_page_nr, size_t offset, size_t *to_copy);
/**
* kbase_mem_copy_from_extres() - Copy from external resources.
*
@ -333,18 +390,6 @@ void kbasep_complete_triggered_soft_events(struct kbase_context *kctx, u64 evt);
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
*
@ -360,6 +405,24 @@ static inline bool kbase_pm_is_suspending(struct kbase_device *kbdev)
return kbdev->pm.suspending;
}
#ifdef CONFIG_MALI_ARBITER_SUPPORT
/*
* Check whether a gpu lost is in progress
*
* @kbdev: The kbase device structure for the device (must be a valid pointer)
*
* Indicates whether a gpu lost has been received and jobs are no longer
* being scheduled
*
* Return: false if gpu is lost
* Return: != false otherwise
*/
static inline bool kbase_pm_is_gpu_lost(struct kbase_device *kbdev)
{
return kbdev->pm.gpu_lost;
}
#endif
/**
* kbase_pm_is_active - Determine whether the GPU is active
*
@ -446,6 +509,8 @@ static inline struct kbase_jd_atom *kbase_jd_atom_from_id(
* and during context creation.
*
* @param kbdev The kbase device
*
* Return: 0 on success and non-zero value on failure.
*/
void kbase_disjoint_init(struct kbase_device *kbdev);
@ -507,181 +572,6 @@ void kbase_disjoint_state_down(struct kbase_device *kbdev);
#define UINT64_MAX ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
#endif
#if KBASE_TRACE_ENABLE
void kbasep_trace_debugfs_init(struct kbase_device *kbdev);
#ifndef CONFIG_MALI_BIFROST_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_BIFROST_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_BIFROST_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_BIFROST_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_BIFROST_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_BIFROST_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)
/** 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_BIFROST_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_BIFROST_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)
#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);
#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_MALI_BIFROST_NO_MALI)
/* kbase_io_history_init - initialize data struct for register access history
@ -731,5 +621,4 @@ int kbase_io_history_resize(struct kbase_io_history *h, u16 new_size);
#endif /* CONFIG_DEBUG_FS */
#endif

View File

@ -1,209 +0,0 @@
/*
*
* (C) COPYRIGHT 2013-2015,2017-2018 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#include <linux/dma-mapping.h>
#include <mali_kbase.h>
#include <mali_kbase_10969_workaround.h>
/* 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;
struct tagged_addr *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 (kbase_is_region_invalid_or_free(region))
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 = as_page(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 = as_page(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 = as_page(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 = as_page(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;
}

View File

@ -1,37 +0,0 @@
/*
*
* (C) COPYRIGHT 2013-2014, 2018 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_10969_WORKAROUND_
#define _KBASE_10969_WORKAROUND_
/**
* kbasep_10969_workaround_clamp_coordinates - Apply the WA to clamp the restart indices
* @katom: atom representing the fragment job for which the WA has to be applied
*
* This workaround 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, it 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.
*/
int kbasep_10969_workaround_clamp_coordinates(struct kbase_jd_atom *katom);
#endif /* _KBASE_10969_WORKAROUND_ */

View File

@ -24,6 +24,7 @@
#include <mali_kbase.h>
#include <mali_kbase_as_fault_debugfs.h>
#include <device/mali_kbase_device.h>
#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_MALI_BIFROST_DEBUG
@ -36,7 +37,7 @@ static int kbase_as_fault_read(struct seq_file *sfile, void *data)
const struct list_head *kbdev_list;
struct kbase_device *kbdev = NULL;
kbdev_list = kbase_dev_list_get();
kbdev_list = kbase_device_get_list();
list_for_each(entry, kbdev_list) {
kbdev = list_entry(entry, struct kbase_device, entry);
@ -53,7 +54,7 @@ static int kbase_as_fault_read(struct seq_file *sfile, void *data)
}
kbase_dev_list_put(kbdev_list);
kbase_device_put_list(kbdev_list);
return 0;
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2013-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2013-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -33,27 +33,6 @@
/* Include mandatory definitions per platform */
#include <mali_kbase_config_platform.h>
/**
* 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.
@ -211,5 +190,24 @@ enum {
*/
#define DEFAULT_GPU_FREQ_KHZ_MAX (5000)
/**
* Default timeout for task execution on an endpoint
*
* Number of GPU clock cycles before the driver terminates a task that is
* making no forward progress on an endpoint (e.g. shader core).
* Value chosen is equivalent to the time after which a job is hard stopped
* which is 5 seconds (assuming the GPU is usually clocked at ~500 MHZ).
*/
#define DEFAULT_PROGRESS_TIMEOUT ((u64)5 * 500 * 1024 * 1024)
/**
* Default threshold at which to switch to incremental rendering
*
* Fraction of the maximum size of an allocation that grows on GPU page fault
* that can be used up before the driver switches to incremental rendering,
* in 256ths. 0 means disable incremental rendering.
*/
#define DEFAULT_IR_THRESHOLD (192)
#endif /* _KBASE_CONFIG_DEFAULTS_H_ */

View File

@ -1,334 +0,0 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Base kernel context APIs
*/
#include <mali_kbase.h>
#include <mali_midg_regmap.h>
#include <mali_kbase_mem_linux.h>
#include <mali_kbase_dma_fence.h>
#include <mali_kbase_ctx_sched.h>
#include <mali_kbase_mem_pool_group.h>
#include <mali_kbase_tracepoints.h>
struct kbase_context *
kbase_create_context(struct kbase_device *kbdev, bool is_compat,
base_context_create_flags const flags,
unsigned long const api_version,
struct file *const filp)
{
struct kbase_context *kctx;
int err;
struct page *p;
struct kbasep_js_kctx_info *js_kctx_info = NULL;
unsigned long irq_flags = 0;
const unsigned long cookies_mask = KBASE_COOKIE_MASK;
if (WARN_ON(!kbdev))
goto out;
/* Validate flags */
if (WARN_ON(flags != (flags & BASEP_CONTEXT_CREATE_KERNEL_FLAGS)))
goto out;
/* 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;
atomic_set(&kctx->refcount, 0);
if (is_compat)
kbase_ctx_flag_set(kctx, KCTX_COMPAT);
#if defined(CONFIG_64BIT)
else
kbase_ctx_flag_set(kctx, KCTX_FORCE_SAME_VA);
#endif /* !defined(CONFIG_64BIT) */
spin_lock_init(&kctx->mm_update_lock);
kctx->process_mm = NULL;
atomic_set(&kctx->nonmapped_pages, 0);
atomic_set(&kctx->permanent_mapped_pages, 0);
kctx->slots_pullable = 0;
kctx->tgid = current->tgid;
kctx->pid = current->pid;
err = kbase_mem_pool_group_init(&kctx->mem_pools, kbdev,
&kbdev->mem_pool_defaults, &kbdev->mem_pools);
if (err)
goto free_kctx;
err = kbase_mem_evictable_init(kctx);
if (err)
goto free_both_pools;
atomic_set(&kctx->used_pages, 0);
err = kbase_jd_init(kctx);
if (err)
goto deinit_evictable;
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);
spin_lock_init(&kctx->mem_partials_lock);
INIT_LIST_HEAD(&kctx->mem_partials);
INIT_LIST_HEAD(&kctx->waiting_soft_jobs);
spin_lock_init(&kctx->waiting_soft_jobs_lock);
err = kbase_dma_fence_init(kctx);
if (err)
goto free_event;
err = kbase_mmu_init(kbdev, &kctx->mmu, kctx,
base_context_mmu_group_id_get(flags));
if (err)
goto term_dma_fence;
p = kbase_mem_alloc_page(
&kctx->mem_pools.small[KBASE_MEM_GROUP_SINK]);
if (!p)
goto no_sink_page;
kctx->aliasing_sink_page = as_tagged(page_to_phys(p));
init_waitqueue_head(&kctx->event_queue);
bitmap_copy(kctx->cookies, &cookies_mask, BITS_PER_LONG);
/* Make sure page 0 is not used... */
err = kbase_region_tracker_init(kctx);
if (err)
goto no_region_tracker;
err = kbase_sticky_resource_init(kctx);
if (err)
goto no_sticky;
err = kbase_jit_init(kctx);
if (err)
goto no_jit;
#ifdef CONFIG_GPU_TRACEPOINTS
atomic_set(&kctx->jctx.work_id, 0);
#endif
kctx->id = atomic_add_return(1, &(kbdev->ctx_num)) - 1;
mutex_init(&kctx->legacy_hwcnt_lock);
kbase_timer_setup(&kctx->soft_job_timeout,
kbasep_soft_job_timeout_worker);
mutex_lock(&kbdev->kctx_list_lock);
list_add(&kctx->kctx_list_link, &kbdev->kctx_list);
KBASE_TLSTREAM_TL_NEW_CTX(kbdev, kctx, kctx->id, (u32)(kctx->tgid));
mutex_unlock(&kbdev->kctx_list_lock);
kctx->api_version = api_version;
kctx->filp = filp;
js_kctx_info = &kctx->jctx.sched_info;
mutex_lock(&js_kctx_info->ctx.jsctx_mutex);
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, irq_flags);
/* Translate the flags */
if ((flags & BASE_CONTEXT_SYSTEM_MONITOR_SUBMIT_DISABLED) == 0)
kbase_ctx_flag_clear(kctx, KCTX_SUBMIT_DISABLED);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, irq_flags);
mutex_unlock(&js_kctx_info->ctx.jsctx_mutex);
return kctx;
no_jit:
kbase_gpu_vm_lock(kctx);
kbase_sticky_resource_term(kctx);
kbase_gpu_vm_unlock(kctx);
no_sticky:
kbase_region_tracker_term(kctx);
no_region_tracker:
kbase_mem_pool_free(
&kctx->mem_pools.small[KBASE_MEM_GROUP_SINK], p, false);
no_sink_page:
kbase_mmu_term(kbdev, &kctx->mmu);
term_dma_fence:
kbase_dma_fence_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);
deinit_evictable:
kbase_mem_evictable_deinit(kctx);
free_both_pools:
kbase_mem_pool_group_term(&kctx->mem_pools);
free_kctx:
vfree(kctx);
out:
return NULL;
}
KBASE_EXPORT_SYMBOL(kbase_create_context);
static void kbase_reg_pending_dtor(struct kbase_device *kbdev,
struct kbase_va_region *reg)
{
dev_dbg(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);
}
void kbase_destroy_context(struct kbase_context *kctx)
{
struct kbase_device *kbdev;
int pages;
unsigned long pending_regions_to_clean;
unsigned long flags;
struct page *p;
if (WARN_ON(!kctx))
return;
kbdev = kctx->kbdev;
if (WARN_ON(!kbdev))
return;
mutex_lock(&kbdev->kctx_list_lock);
KBASE_TLSTREAM_TL_DEL_CTX(kbdev, kctx);
list_del(&kctx->kctx_list_link);
mutex_unlock(&kbdev->kctx_list_lock);
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_mem_pool_group_mark_dying(&kctx->mem_pools);
kbase_jd_zap_context(kctx);
/* We have already waited for the jobs to complete (and hereafter there
* can be no more submissions for the context). However the wait could
* have timedout and there could still be work items in flight that
* would do the completion processing of jobs.
* kbase_jd_exit() will destroy the 'job_done_wq'. And destroying the wq
* will cause it do drain and implicitly wait for those work items to
* complete.
*/
kbase_jd_exit(kctx);
#ifdef CONFIG_DEBUG_FS
/* Removing the rest of the debugfs entries here as we want to keep the
* atom debugfs interface alive until all atoms have completed. This
* is useful for debugging hung contexts. */
debugfs_remove_recursive(kctx->kctx_dentry);
kbase_debug_job_fault_context_term(kctx);
#endif
kbase_event_cleanup(kctx);
/*
* JIT must be terminated before the code below as it must be called
* without the region lock being held.
* The code above ensures no new JIT allocations can be made by
* by the time we get to this point of context tear down.
*/
kbase_jit_term(kctx);
kbase_gpu_vm_lock(kctx);
kbase_sticky_resource_term(kctx);
/* drop the aliasing sink page now that it can't be mapped anymore */
p = as_page(kctx->aliasing_sink_page);
kbase_mem_pool_free(&kctx->mem_pools.small[KBASE_MEM_GROUP_SINK],
p, false);
/* free pending region setups */
pending_regions_to_clean = KBASE_COOKIE_MASK;
bitmap_andnot(&pending_regions_to_clean, &pending_regions_to_clean,
kctx->cookies, BITS_PER_LONG);
while (pending_regions_to_clean) {
unsigned int cookie = find_first_bit(&pending_regions_to_clean,
BITS_PER_LONG);
BUG_ON(!kctx->pending_regions[cookie]);
kbase_reg_pending_dtor(kbdev, kctx->pending_regions[cookie]);
kctx->pending_regions[cookie] = NULL;
bitmap_clear(&pending_regions_to_clean, cookie, 1);
}
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_dma_fence_term(kctx);
mutex_lock(&kbdev->mmu_hw_mutex);
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, flags);
kbase_ctx_sched_remove_ctx(kctx);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags);
mutex_unlock(&kbdev->mmu_hw_mutex);
kbase_mmu_term(kbdev, &kctx->mmu);
pages = atomic_read(&kctx->used_pages);
if (pages != 0)
dev_warn(kbdev->dev, "%s: %d pages in use!\n", __func__, pages);
kbase_mem_evictable_deinit(kctx);
kbase_mem_pool_group_term(&kctx->mem_pools);
WARN_ON(atomic_read(&kctx->nonmapped_pages) != 0);
vfree(kctx);
kbase_pm_context_idle(kbdev);
}
KBASE_EXPORT_SYMBOL(kbase_destroy_context);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/*
*
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
* (C) COPYRIGHT 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
*/
#ifndef _KBASE_CS_EXPERIMENTAL_H_
#define _KBASE_CS_EXPERIMENTAL_H_
#include <linux/kernel.h>
/**
* mali_kbase_print_cs_experimental() - Print a string for every Core Services
* experimental feature that is enabled
*/
static inline void mali_kbase_print_cs_experimental(void)
{
#if MALI_JIT_PRESSURE_LIMIT
pr_info("mali_kbase: JIT_PRESSURE_LIMIT (experimental) enabled");
#endif /* MALI_JIT_PRESSURE_LIMIT */
#if MALI_INCREMENTAL_RENDERING
pr_info("mali_kbase: INCREMENTAL_RENDERING (experimental) enabled");
#endif /* MALI_INCREMENTAL_RENDERING */
}
#endif /* _KBASE_CS_EXPERIMENTAL_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2017-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2017-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -23,7 +23,23 @@
#include <mali_kbase.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_defs.h>
#include "mali_kbase_ctx_sched.h"
#include "tl/mali_kbase_tracepoints.h"
/* Helper for ktrace */
#if KBASE_KTRACE_ENABLE
static int kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)
{
return atomic_read(&kctx->refcount);
}
#else /* KBASE_KTRACE_ENABLE */
static int kbase_ktrace_get_ctx_refcnt(struct kbase_context *kctx)
{
CSTD_UNUSED(kctx);
return 0;
}
#endif /* KBASE_KTRACE_ENABLE */
int kbase_ctx_sched_init(struct kbase_device *kbdev)
{
@ -106,11 +122,15 @@ int kbase_ctx_sched_retain_ctx(struct kbase_context *kctx)
if (prev_kctx) {
WARN_ON(atomic_read(&prev_kctx->refcount) != 0);
kbase_mmu_disable(prev_kctx);
KBASE_TLSTREAM_TL_KBASE_CTX_UNASSIGN_AS(
kbdev, prev_kctx->id);
prev_kctx->as_nr = KBASEP_AS_NR_INVALID;
}
kctx->as_nr = free_as;
kbdev->as_to_kctx[free_as] = kctx;
KBASE_TLSTREAM_TL_KBASE_CTX_ASSIGN_AS(
kbdev, kctx->id, free_as);
kbase_mmu_update(kbdev, &kctx->mmu,
kctx->as_nr);
}
@ -142,11 +162,23 @@ void kbase_ctx_sched_retain_ctx_refcount(struct kbase_context *kctx)
void kbase_ctx_sched_release_ctx(struct kbase_context *kctx)
{
struct kbase_device *const kbdev = kctx->kbdev;
int new_ref_count;
lockdep_assert_held(&kbdev->hwaccess_lock);
if (atomic_dec_return(&kctx->refcount) == 0)
new_ref_count = atomic_dec_return(&kctx->refcount);
if (new_ref_count == 0) {
kbdev->as_free |= (1u << kctx->as_nr);
if (kbase_ctx_flag(kctx, KCTX_AS_DISABLED_ON_FAULT)) {
KBASE_TLSTREAM_TL_KBASE_CTX_UNASSIGN_AS(
kbdev, kctx->id);
kbdev->as_to_kctx[kctx->as_nr] = NULL;
kctx->as_nr = KBASEP_AS_NR_INVALID;
kbase_ctx_flag_clear(kctx, KCTX_AS_DISABLED_ON_FAULT);
}
}
KBASE_KTRACE_ADD(kbdev, SCHED_RELEASE_CTX, kctx, new_ref_count);
}
void kbase_ctx_sched_remove_ctx(struct kbase_context *kctx)
@ -162,6 +194,7 @@ void kbase_ctx_sched_remove_ctx(struct kbase_context *kctx)
if (kbdev->pm.backend.gpu_powered)
kbase_mmu_disable(kctx);
KBASE_TLSTREAM_TL_KBASE_CTX_UNASSIGN_AS(kbdev, kctx->id);
kbdev->as_to_kctx[kctx->as_nr] = NULL;
kctx->as_nr = KBASEP_AS_NR_INVALID;
}
@ -186,15 +219,126 @@ void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev)
kbase_mmu_update(kbdev, &kctx->mmu,
kctx->as_nr);
kbase_ctx_flag_clear(kctx,
KCTX_AS_DISABLED_ON_FAULT);
} else {
/* This context might have been assigned an
* AS before, clear it.
*/
kbdev->as_to_kctx[kctx->as_nr] = NULL;
kctx->as_nr = KBASEP_AS_NR_INVALID;
if (kctx->as_nr != KBASEP_AS_NR_INVALID) {
KBASE_TLSTREAM_TL_KBASE_CTX_UNASSIGN_AS(
kbdev, kctx->id);
kbdev->as_to_kctx[kctx->as_nr] = NULL;
kctx->as_nr = KBASEP_AS_NR_INVALID;
}
}
} else {
kbase_mmu_disable_as(kbdev, i);
}
}
}
struct kbase_context *kbase_ctx_sched_as_to_ctx_refcount(
struct kbase_device *kbdev, size_t as_nr)
{
unsigned long flags;
struct kbase_context *found_kctx = NULL;
if (WARN_ON(kbdev == NULL))
return NULL;
if (WARN_ON(as_nr >= BASE_MAX_NR_AS))
return NULL;
spin_lock_irqsave(&kbdev->hwaccess_lock, flags);
found_kctx = kbdev->as_to_kctx[as_nr];
if (found_kctx != NULL)
kbase_ctx_sched_retain_ctx_refcount(found_kctx);
spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags);
return found_kctx;
}
struct kbase_context *kbase_ctx_sched_as_to_ctx(struct kbase_device *kbdev,
size_t as_nr)
{
struct kbase_context *found_kctx;
if (WARN_ON(kbdev == NULL))
return NULL;
if (WARN_ON(as_nr >= BASE_MAX_NR_AS))
return NULL;
found_kctx = kbdev->as_to_kctx[as_nr];
if (WARN_ON(!found_kctx))
return NULL;
if (WARN_ON(atomic_read(&found_kctx->refcount) <= 0))
return NULL;
return found_kctx;
}
bool kbase_ctx_sched_inc_refcount_nolock(struct kbase_context *kctx)
{
bool result = false;
int as_nr;
if (WARN_ON(kctx == NULL))
return result;
lockdep_assert_held(&kctx->kbdev->hwaccess_lock);
as_nr = kctx->as_nr;
if (atomic_read(&kctx->refcount) > 0) {
KBASE_DEBUG_ASSERT(as_nr >= 0);
kbase_ctx_sched_retain_ctx_refcount(kctx);
KBASE_KTRACE_ADD(kctx->kbdev, SCHED_RETAIN_CTX_NOLOCK, kctx,
kbase_ktrace_get_ctx_refcnt(kctx));
result = true;
}
return result;
}
bool kbase_ctx_sched_inc_refcount(struct kbase_context *kctx)
{
unsigned long flags;
bool result = false;
if (WARN_ON(kctx == NULL))
return result;
if (WARN_ON(kctx->kbdev == NULL))
return result;
mutex_lock(&kctx->kbdev->mmu_hw_mutex);
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, flags);
result = kbase_ctx_sched_inc_refcount_nolock(kctx);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags);
mutex_unlock(&kctx->kbdev->mmu_hw_mutex);
return result;
}
void kbase_ctx_sched_release_ctx_lock(struct kbase_context *kctx)
{
unsigned long flags;
if (WARN_ON(!kctx))
return;
spin_lock_irqsave(&kctx->kbdev->hwaccess_lock, flags);
if (!WARN_ON(kctx->as_nr == KBASEP_AS_NR_INVALID) &&
!WARN_ON(atomic_read(&kctx->refcount) <= 0))
kbase_ctx_sched_release_ctx(kctx);
spin_unlock_irqrestore(&kctx->kbdev->hwaccess_lock, flags);
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2017-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2017-2018, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -132,4 +132,78 @@ void kbase_ctx_sched_remove_ctx(struct kbase_context *kctx);
*/
void kbase_ctx_sched_restore_all_as(struct kbase_device *kbdev);
/**
* kbase_ctx_sched_as_to_ctx_refcount - Lookup a context based on its current
* address space and ensure that is stays scheduled in
* @kbdev: The device for which the returned context must belong
* @as_nr: address space assigned to the context of interest
*
* The context is refcounted as being busy to prevent it from scheduling
* out. It must be released with kbase_ctx_sched_release_ctx() when it is no
* longer required to stay scheduled in.
*
* This function can safely be called from IRQ context.
*
* The following locking conditions are made on the caller:
* * it must not hold the kbase_device::hwaccess_lock, because it will be used
* internally.
*
* Return: a valid struct kbase_context on success, which has been refcounted
* as being busy or return NULL on failure, indicating that no context was found
* in as_nr.
*/
struct kbase_context *kbase_ctx_sched_as_to_ctx_refcount(
struct kbase_device *kbdev, size_t as_nr);
/**
* kbase_ctx_sched_as_to_ctx - Lookup a context based on its current address
* space
* @kbdev: The device for which the returned context must belong
* @as_nr: address space assigned to the context of interest
*
* Return: a valid struct kbase_context on success or NULL on failure,
* indicating that no context was found in as_nr.
*/
struct kbase_context *kbase_ctx_sched_as_to_ctx(struct kbase_device *kbdev,
size_t as_nr);
/**
* kbase_ctx_sched_inc_refcount_nolock - Refcount a context as being busy,
* preventing it from being scheduled out.
* @kctx: Context to be refcounted
*
* The following locks must be held by the caller:
* * kbase_device::mmu_hw_mutex
* * kbase_device::hwaccess_lock
*
* Return: true if refcount succeeded, and the context will not be scheduled
* out, false if the refcount failed (because the context is being/has been
* scheduled out).
*/
bool kbase_ctx_sched_inc_refcount_nolock(struct kbase_context *kctx);
/**
* kbase_ctx_sched_inc_refcount - Refcount a context as being busy, preventing
* it from being scheduled out.
* @kctx: Context to be refcounted
*
* The following locking conditions are made on the caller:
* * it must not hold kbase_device::mmu_hw_mutex and
* kbase_device::hwaccess_lock, because they will be used internally.
*
* Return: true if refcount succeeded, and the context will not be scheduled
* out, false if the refcount failed (because the context is being/has been
* scheduled out).
*/
bool kbase_ctx_sched_inc_refcount(struct kbase_context *kctx);
/**
* kbase_ctx_sched_release_ctx_lock - Release a reference count of a context
* @kctx: Context for which refcount should be decreased
*
* Effectivelly, this is a wrapper for kbase_ctx_sched_release_ctx, but
* kbase_device::hwaccess_lock is required NOT to be locked.
*/
void kbase_ctx_sched_release_ctx_lock(struct kbase_context *kctx);
#endif /* _KBASE_CTX_SCHED_H_ */

View File

@ -233,6 +233,12 @@ static int debug_mem_open(struct inode *i, struct file *file)
goto out;
}
ret = debug_mem_zone_open(&kctx->reg_rbtree_exec, mem_data);
if (0 != ret) {
kbase_gpu_vm_unlock(kctx);
goto out;
}
kbase_gpu_vm_unlock(kctx);
((struct seq_file *)file->private_data)->private = mem_data;

File diff suppressed because it is too large Load Diff

View File

@ -1,515 +0,0 @@
/*
*
* (C) COPYRIGHT 2010-2019 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* 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_hwaccess_instr.h>
#include <mali_kbase_hw.h>
#include <mali_kbase_config_defaults.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
#define DEBUG_MESSAGE_SIZE 256
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)
{
kbdev->as[i].number = i;
kbdev->as[i].bf_data.addr = 0ULL;
kbdev->as[i].pf_data.addr = 0ULL;
kbdev->as[i].pf_wq = alloc_workqueue("mali_mmu%d", 0, 1, i);
if (!kbdev->as[i].pf_wq)
return -EINVAL;
INIT_WORK(&kbdev->as[i].work_pagefault, page_fault_worker);
INIT_WORK(&kbdev->as[i].work_busfault, bus_fault_worker);
return 0;
}
static void kbase_device_as_term(struct kbase_device *kbdev, int i)
{
destroy_workqueue(kbdev->as[i].pf_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 err;
#ifdef CONFIG_ARM64
struct device_node *np = NULL;
#endif /* CONFIG_ARM64 */
spin_lock_init(&kbdev->mmu_mask_change);
mutex_init(&kbdev->mmu_hw_mutex);
#ifdef CONFIG_ARM64
kbdev->cci_snoop_enabled = false;
np = kbdev->dev->of_node;
if (np != NULL) {
if (of_property_read_u32(np, "snoop_enable_smc",
&kbdev->snoop_enable_smc))
kbdev->snoop_enable_smc = 0;
if (of_property_read_u32(np, "snoop_disable_smc",
&kbdev->snoop_disable_smc))
kbdev->snoop_disable_smc = 0;
/* Either both or none of the calls should be provided. */
if (!((kbdev->snoop_disable_smc == 0
&& kbdev->snoop_enable_smc == 0)
|| (kbdev->snoop_disable_smc != 0
&& kbdev->snoop_enable_smc != 0))) {
WARN_ON(1);
err = -EINVAL;
goto fail;
}
}
#endif /* CONFIG_ARM64 */
/* 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);
kbase_gpuprops_set_features(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;
init_waitqueue_head(&kbdev->cache_clean_wait);
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;
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_AARCH64_MMU))
kbdev->mmu_mode = kbase_mmu_mode_get_aarch64();
else
kbdev->mmu_mode = kbase_mmu_mode_get_lpae();
mutex_init(&kbdev->kctx_list_lock);
INIT_LIST_HEAD(&kbdev->kctx_list);
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);
WARN_ON(!list_empty(&kbdev->kctx_list));
#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);
}
/*
* Device trace functions
*/
#if KBASE_TRACE_ENABLE
static int kbasep_trace_init(struct kbase_device *kbdev)
{
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);
return 0;
}
static void kbasep_trace_term(struct kbase_device *kbdev)
{
kfree(kbdev->trace_rbuf);
}
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);
}
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;
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);
getnstimeofday(&trace_msg->timestamp);
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;
}
static const struct file_operations kbasep_trace_debugfs_fops = {
.owner = THIS_MODULE,
.open = kbasep_trace_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
void kbasep_trace_debugfs_init(struct kbase_device *kbdev)
{
debugfs_create_file("mali_trace", S_IRUGO,
kbdev->mali_debugfs_directory, kbdev,
&kbasep_trace_debugfs_fops);
}
#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 */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2017 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2017,2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -114,6 +114,8 @@ kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info *info,
ww_acquire_fini(ctx);
}
/**
* kbase_dma_fence_queue_work() - Queue work to handle @katom
* @katom: Pointer to atom for which to queue work

View File

@ -0,0 +1,442 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
/*
* Implementation of the dummy job execution workaround for the GPU hang issue.
*/
#include <mali_kbase.h>
#include <backend/gpu/mali_kbase_device_internal.h>
#include <mali_kbase_dummy_job_wa.h>
#include <linux/firmware.h>
#include <linux/delay.h>
#define DUMMY_JOB_WA_BINARY_NAME "valhall-1691526.wa"
struct wa_header {
u16 signature;
u16 version;
u32 info_offset;
} __packed;
struct wa_v2_info {
u64 jc;
u32 js;
u32 blob_offset;
u64 flags;
} __packed;
struct wa_blob {
u64 base;
u32 size;
u32 map_flags;
u32 payload_offset;
u32 blob_offset;
} __packed;
static bool in_range(const u8 *base, const u8 *end, off_t off, size_t sz)
{
return !(end - base - off < sz);
}
static u32 wait_any(struct kbase_device *kbdev, off_t offset, u32 bits)
{
int loop;
const int timeout = 100;
u32 val;
for (loop = 0; loop < timeout; loop++) {
val = kbase_reg_read(kbdev, offset);
if (val & bits)
break;
udelay(10);
}
if (loop == timeout) {
dev_err(kbdev->dev,
"Timeout reading register 0x%lx, bits 0x%lx, last read was 0x%lx\n",
(unsigned long)offset, (unsigned long)bits,
(unsigned long)val);
}
return (val & bits);
}
static int wait(struct kbase_device *kbdev, off_t offset, u32 bits, bool set)
{
int loop;
const int timeout = 100;
u32 val;
u32 target = 0;
if (set)
target = bits;
for (loop = 0; loop < timeout; loop++) {
val = kbase_reg_read(kbdev, (offset));
if ((val & bits) == target)
break;
udelay(10);
}
if (loop == timeout) {
dev_err(kbdev->dev,
"Timeout reading register 0x%lx, bits 0x%lx, last read was 0x%lx\n",
(unsigned long)offset, (unsigned long)bits,
(unsigned long)val);
return -ETIMEDOUT;
}
return 0;
}
static inline int run_job(struct kbase_device *kbdev, int as, int slot,
u64 cores, u64 jc)
{
u32 done;
/* setup job */
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_HEAD_NEXT_LO),
jc & U32_MAX);
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_HEAD_NEXT_HI),
jc >> 32);
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_AFFINITY_NEXT_LO),
cores & U32_MAX);
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_AFFINITY_NEXT_HI),
cores >> 32);
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_CONFIG_NEXT),
JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK | as);
/* go */
kbase_reg_write(kbdev, JOB_SLOT_REG(slot, JS_COMMAND_NEXT),
JS_COMMAND_START);
/* wait for the slot to finish (done, error) */
done = wait_any(kbdev, JOB_CONTROL_REG(JOB_IRQ_RAWSTAT),
(1ul << (16+slot)) | (1ul << slot));
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_CLEAR), done);
if (done != (1ul << slot)) {
dev_err(kbdev->dev,
"Failed to run WA job on slot %d cores 0x%llx: done 0x%lx\n",
slot, (unsigned long long)cores,
(unsigned long)done);
dev_err(kbdev->dev, "JS_STATUS on failure: 0x%x\n",
kbase_reg_read(kbdev, JOB_SLOT_REG(slot, JS_STATUS)));
return -EFAULT;
} else {
return 0;
}
}
/* To be called after power up & MMU init, but before everything else */
int kbase_dummy_job_wa_execute(struct kbase_device *kbdev, u64 cores)
{
int as;
int slot;
u64 jc;
int failed = 0;
int runs = 0;
u32 old_gpu_mask;
u32 old_job_mask;
if (!kbdev)
return -EFAULT;
if (!kbdev->dummy_job_wa.ctx)
return -EFAULT;
as = kbdev->dummy_job_wa.ctx->as_nr;
slot = kbdev->dummy_job_wa.slot;
jc = kbdev->dummy_job_wa.jc;
/* mask off all but MMU IRQs */
old_gpu_mask = kbase_reg_read(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK));
old_job_mask = kbase_reg_read(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK));
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), 0);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), 0);
/* power up requested cores */
kbase_reg_write(kbdev, SHADER_PWRON_LO, (cores & U32_MAX));
kbase_reg_write(kbdev, SHADER_PWRON_HI, (cores >> 32));
if (kbdev->dummy_job_wa.flags & KBASE_DUMMY_JOB_WA_FLAG_WAIT_POWERUP) {
/* wait for power-ups */
wait(kbdev, SHADER_READY_LO, (cores & U32_MAX), true);
if (cores >> 32)
wait(kbdev, SHADER_READY_HI, (cores >> 32), true);
}
if (kbdev->dummy_job_wa.flags & KBASE_DUMMY_JOB_WA_FLAG_SERIALIZE) {
int i;
/* do for each requested core */
for (i = 0; i < sizeof(cores) * 8; i++) {
u64 affinity;
affinity = 1ull << i;
if (!(cores & affinity))
continue;
if (run_job(kbdev, as, slot, affinity, jc))
failed++;
runs++;
}
} else {
if (run_job(kbdev, as, slot, cores, jc))
failed++;
runs++;
}
if (kbdev->dummy_job_wa.flags &
KBASE_DUMMY_JOB_WA_FLAG_LOGICAL_SHADER_POWER) {
/* power off shader cores (to reduce any dynamic leakage) */
kbase_reg_write(kbdev, SHADER_PWROFF_LO, (cores & U32_MAX));
kbase_reg_write(kbdev, SHADER_PWROFF_HI, (cores >> 32));
/* wait for power off complete */
wait(kbdev, SHADER_READY_LO, (cores & U32_MAX), false);
wait(kbdev, SHADER_PWRTRANS_LO, (cores & U32_MAX), false);
if (cores >> 32) {
wait(kbdev, SHADER_READY_HI, (cores >> 32), false);
wait(kbdev, SHADER_PWRTRANS_HI, (cores >> 32), false);
}
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_CLEAR), U32_MAX);
}
/* restore IRQ masks */
kbase_reg_write(kbdev, GPU_CONTROL_REG(GPU_IRQ_MASK), old_gpu_mask);
kbase_reg_write(kbdev, JOB_CONTROL_REG(JOB_IRQ_MASK), old_job_mask);
if (failed)
dev_err(kbdev->dev,
"WA complete with %d failures out of %d runs\n", failed,
runs);
return failed ? -EFAULT : 0;
}
static ssize_t show_dummy_job_wa_info(struct device * const dev,
struct device_attribute * const attr, char * const buf)
{
struct kbase_device *const kbdev = dev_get_drvdata(dev);
int err;
if (!kbdev || !kbdev->dummy_job_wa.ctx)
return -ENODEV;
err = scnprintf(buf, PAGE_SIZE, "slot %u flags %llx\n",
kbdev->dummy_job_wa.slot, kbdev->dummy_job_wa.flags);
return err;
}
static DEVICE_ATTR(dummy_job_wa_info, 0444, show_dummy_job_wa_info, NULL);
static bool wa_blob_load_needed(struct kbase_device *kbdev)
{
if (of_machine_is_compatible("arm,juno"))
return false;
if (kbase_hw_has_issue(kbdev, BASE_HW_ISSUE_TTRX_3485))
return true;
return false;
}
int kbase_dummy_job_wa_load(struct kbase_device *kbdev)
{
const struct firmware *firmware;
static const char wa_name[] = DUMMY_JOB_WA_BINARY_NAME;
const u32 signature = 0x4157;
const u32 version = 2;
const u8 *fw_end;
const u8 *fw;
const struct wa_header *header;
const struct wa_v2_info *v2_info;
u32 blob_offset;
int err;
struct kbase_context *kctx;
if (!wa_blob_load_needed(kbdev))
return 0;
/* load the wa */
err = request_firmware(&firmware, wa_name, kbdev->dev);
if (err) {
dev_err(kbdev->dev, "WA blob missing. Please refer to the Arm Mali DDK Valhall Release Notes, "
"Part number DC-06002 or contact support-mali@arm.com - driver probe will be failed");
return -ENODEV;
}
kctx = kbase_create_context(kbdev, true,
BASE_CONTEXT_CREATE_FLAG_NONE, 0,
NULL);
if (!kctx) {
dev_err(kbdev->dev, "Failed to create WA context\n");
goto no_ctx;
}
fw = firmware->data;
fw_end = fw + firmware->size;
dev_dbg(kbdev->dev, "Loaded firmware of size %zu bytes\n",
firmware->size);
if (!in_range(fw, fw_end, 0, sizeof(*header))) {
dev_err(kbdev->dev, "WA too small\n");
goto bad_fw;
}
header = (const struct wa_header *)(fw + 0);
if (header->signature != signature) {
dev_err(kbdev->dev, "WA signature failure: 0x%lx\n",
(unsigned long)header->signature);
goto bad_fw;
}
if (header->version != version) {
dev_err(kbdev->dev, "WA version 0x%lx not supported\n",
(unsigned long)header->version);
goto bad_fw;
}
if (!in_range(fw, fw_end, header->info_offset, sizeof(*v2_info))) {
dev_err(kbdev->dev, "WA info offset out of bounds\n");
goto bad_fw;
}
v2_info = (const struct wa_v2_info *)(fw + header->info_offset);
if (v2_info->flags & ~KBASE_DUMMY_JOB_WA_FLAGS) {
dev_err(kbdev->dev, "Unsupported WA flag(s): 0x%llx\n",
(unsigned long long)v2_info->flags);
goto bad_fw;
}
kbdev->dummy_job_wa.slot = v2_info->js;
kbdev->dummy_job_wa.jc = v2_info->jc;
kbdev->dummy_job_wa.flags = v2_info->flags;
blob_offset = v2_info->blob_offset;
while (blob_offset) {
const struct wa_blob *blob;
size_t nr_pages;
u64 flags;
u64 gpu_va;
struct kbase_va_region *va_region;
if (!in_range(fw, fw_end, blob_offset, sizeof(*blob))) {
dev_err(kbdev->dev, "Blob offset out-of-range: 0x%lx\n",
(unsigned long)blob_offset);
goto bad_fw;
}
blob = (const struct wa_blob *)(fw + blob_offset);
if (!in_range(fw, fw_end, blob->payload_offset, blob->size)) {
dev_err(kbdev->dev, "Payload out-of-bounds\n");
goto bad_fw;
}
gpu_va = blob->base;
if (PAGE_ALIGN(gpu_va) != gpu_va) {
dev_err(kbdev->dev, "blob not page aligned\n");
goto bad_fw;
}
nr_pages = PFN_UP(blob->size);
flags = blob->map_flags | BASE_MEM_FLAG_MAP_FIXED;
va_region = kbase_mem_alloc(kctx, nr_pages, nr_pages,
0, &flags, &gpu_va);
if (!va_region) {
dev_err(kbdev->dev, "Failed to allocate for blob\n");
} else {
struct kbase_vmap_struct vmap = { 0 };
const u8 *payload;
void *dst;
/* copy the payload, */
payload = fw + blob->payload_offset;
dst = kbase_vmap(kctx,
va_region->start_pfn << PAGE_SHIFT,
nr_pages << PAGE_SHIFT, &vmap);
if (dst) {
memcpy(dst, payload, blob->size);
kbase_vunmap(kctx, &vmap);
} else {
dev_err(kbdev->dev,
"Failed to copy payload\n");
}
}
blob_offset = blob->blob_offset; /* follow chain */
}
release_firmware(firmware);
kbasep_js_schedule_privileged_ctx(kbdev, kctx);
kbdev->dummy_job_wa.ctx = kctx;
err = sysfs_create_file(&kbdev->dev->kobj,
&dev_attr_dummy_job_wa_info.attr);
if (err)
dev_err(kbdev->dev, "SysFS file creation for dummy job wa failed\n");
return 0;
bad_fw:
kbase_destroy_context(kctx);
no_ctx:
release_firmware(firmware);
return -EFAULT;
}
void kbase_dummy_job_wa_cleanup(struct kbase_device *kbdev)
{
struct kbase_context *wa_ctx;
/* Can be safely called even if the file wasn't created on probe */
sysfs_remove_file(&kbdev->dev->kobj, &dev_attr_dummy_job_wa_info.attr);
wa_ctx = READ_ONCE(kbdev->dummy_job_wa.ctx);
WRITE_ONCE(kbdev->dummy_job_wa.ctx, NULL);
/* make this write visible before we tear down the ctx */
smp_mb();
if (wa_ctx) {
kbasep_js_release_privileged_ctx(kbdev, wa_ctx);
kbase_destroy_context(wa_ctx);
}
}

View File

@ -0,0 +1,45 @@
/*
*
* (C) COPYRIGHT 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* SPDX-License-Identifier: GPL-2.0
*
*/
#ifndef _KBASE_DUMMY_JOB_WORKAROUND_
#define _KBASE_DUMMY_JOB_WORKAROUND_
#define KBASE_DUMMY_JOB_WA_FLAG_SERIALIZE (1ull << 0)
#define KBASE_DUMMY_JOB_WA_FLAG_WAIT_POWERUP (1ull << 1)
#define KBASE_DUMMY_JOB_WA_FLAG_LOGICAL_SHADER_POWER (1ull << 2)
#define KBASE_DUMMY_JOB_WA_FLAGS (KBASE_DUMMY_JOB_WA_FLAG_SERIALIZE | \
KBASE_DUMMY_JOB_WA_FLAG_WAIT_POWERUP | \
KBASE_DUMMY_JOB_WA_FLAG_LOGICAL_SHADER_POWER)
int kbase_dummy_job_wa_load(struct kbase_device *kbdev);
void kbase_dummy_job_wa_cleanup(struct kbase_device *kbdev);
int kbase_dummy_job_wa_execute(struct kbase_device *kbdev, u64 cores);
static inline bool kbase_dummy_job_wa_enabled(struct kbase_device *kbdev)
{
return (kbdev->dummy_job_wa.ctx != NULL);
}
#endif /* _KBASE_DUMMY_JOB_WORKAROUND_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2016,2018-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2016,2018-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -24,7 +24,8 @@
#include <mali_kbase.h>
#include <mali_kbase_debug.h>
#include <mali_kbase_tracepoints.h>
#include <tl/mali_kbase_tracepoints.h>
#include <mali_linux_trace.h>
static struct base_jd_udata kbase_event_process(struct kbase_context *kctx, struct kbase_jd_atom *katom)
{
@ -44,22 +45,12 @@ static struct base_jd_udata kbase_event_process(struct kbase_context *kctx, stru
KBASE_TLSTREAM_TL_DEL_ATOM(kbdev, katom);
katom->status = KBASE_JD_ATOM_STATE_UNUSED;
dev_dbg(kbdev->dev, "Atom %p status to unused\n", (void *)katom);
wake_up(&katom->completed);
return data;
}
int kbase_event_pending(struct kbase_context *ctx)
{
KBASE_DEBUG_ASSERT(ctx);
return (atomic_read(&ctx->event_count) != 0) ||
(atomic_read(&ctx->event_closed) != 0);
}
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;
@ -93,6 +84,7 @@ int kbase_event_dequeue(struct kbase_context *ctx, struct base_jd_event_v2 *ueve
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)
@ -174,22 +166,25 @@ void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *atom)
{
struct kbase_device *kbdev = ctx->kbdev;
dev_dbg(kbdev->dev, "Posting event for atom %p\n", (void *)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 */
dev_dbg(kbdev->dev, "Suppressing event (atom done)\n");
kbase_event_process_noreport(ctx, atom);
return;
}
}
if (atom->core_req & BASEP_JD_REQ_EVENT_NEVER) {
/* Don't report the event */
dev_dbg(kbdev->dev, "Suppressing event (never)\n");
kbase_event_process_noreport(ctx, atom);
return;
}
KBASE_TLSTREAM_TL_ATTRIB_ATOM_STATE(kbdev, atom, TL_ATOM_STATE_POSTED);
if (atom->core_req & BASE_JD_REQ_EVENT_COALESCE) {
/* Don't report the event until other event(s) have completed */
dev_dbg(kbdev->dev, "Deferring event (coalesced)\n");
mutex_lock(&ctx->event_mutex);
list_add_tail(&atom->dep_item[0], &ctx->event_coalesce_list);
++ctx->event_coalesce_count;
@ -203,8 +198,13 @@ void kbase_event_post(struct kbase_context *ctx, struct kbase_jd_atom *atom)
list_add_tail(&atom->dep_item[0], &ctx->event_list);
atomic_add(event_count, &ctx->event_count);
mutex_unlock(&ctx->event_mutex);
dev_dbg(kbdev->dev, "Reporting %d events\n", event_count);
kbase_event_wakeup(ctx);
/* Post-completion latency */
trace_sysgraph(SGR_POST, ctx->id,
kbase_jd_atom_id(ctx, atom));
}
}
KBASE_EXPORT_TEST_API(kbase_event_post);
@ -224,9 +224,7 @@ int kbase_event_init(struct kbase_context *kctx)
INIT_LIST_HEAD(&kctx->event_list);
INIT_LIST_HEAD(&kctx->event_coalesce_list);
mutex_init(&kctx->event_mutex);
atomic_set(&kctx->event_count, 0);
kctx->event_coalesce_count = 0;
atomic_set(&kctx->event_closed, false);
kctx->event_workq = alloc_workqueue("kbase_event", WQ_MEM_RECLAIM, 1);
if (NULL == kctx->event_workq)

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -87,6 +87,7 @@ const struct dma_fence_ops kbase_fence_ops = {
.fence_value_str = kbase_fence_fence_value_str
};
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0))
struct fence *
kbase_fence_out_new(struct kbase_jd_atom *katom)
@ -210,3 +211,4 @@ kbase_fence_add_callback(struct kbase_jd_atom *katom,
return err;
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2018, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -87,6 +87,7 @@ struct dma_fence *kbase_fence_out_new(struct kbase_jd_atom *katom);
} while (0)
#endif
/**
* kbase_fence_out_remove() - Removes the output fence from atom
* @katom: Atom to remove output fence for
@ -268,6 +269,7 @@ bool kbase_fence_free_callbacks(struct kbase_jd_atom *katom);
*/
#define kbase_fence_out_get(katom) dma_fence_get((katom)->dma_fence.fence)
/**
* kbase_fence_put() - Releases a reference to a fence
* @fence: Fence to release reference for.

View File

@ -21,6 +21,7 @@
*/
#include <mali_kbase.h>
#include <device/mali_kbase_device.h>
#ifdef CONFIG_DEBUG_FS
/** Show callback for the @c gpu_memory debugfs file.
@ -40,7 +41,7 @@ static int kbasep_gpu_memory_seq_show(struct seq_file *sfile, void *data)
struct list_head *entry;
const struct list_head *kbdev_list;
kbdev_list = kbase_dev_list_get();
kbdev_list = kbase_device_get_list();
list_for_each(entry, kbdev_list) {
struct kbase_device *kbdev = NULL;
struct kbase_context *kctx;
@ -61,7 +62,7 @@ static int kbasep_gpu_memory_seq_show(struct seq_file *sfile, void *data)
}
mutex_unlock(&kbdev->kctx_list_lock);
}
kbase_dev_list_put(kbdev_list);
kbase_device_put_list(kbdev_list);
return 0;
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
*
* (C) COPYRIGHT 2011-2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -27,30 +28,19 @@
*/
#include <mali_kbase.h>
#include <mali_midg_regmap.h>
#include <gpu/mali_kbase_gpu_regmap.h>
#include <mali_kbase_gpuprops.h>
#include <mali_kbase_hwaccess_gpuprops.h>
#include <mali_kbase_config_defaults.h>
#include "mali_kbase_ioctl.h"
#include <linux/clk.h>
#include <mali_kbase_pm_internal.h>
#include <linux/of_platform.h>
#include <linux/moduleparam.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))
static void kbase_gpuprops_construct_coherent_groups(base_gpu_props * const props)
static void kbase_gpuprops_construct_coherent_groups(
struct base_gpu_props * const props)
{
struct mali_base_gpu_coherent_group *current_group;
u64 group_present;
@ -119,22 +109,28 @@ static void kbase_gpuprops_construct_coherent_groups(base_gpu_props * const prop
/**
* kbase_gpuprops_get_props - Get the GPU configuration
* @gpu_props: The &base_gpu_props structure
* @gpu_props: The &struct 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
* Fill the &struct base_gpu_props structure with values from the GPU
* configuration registers. Only the raw properties are filled in this function.
*
* Return: Zero on success, Linux error code on failure
*/
static void kbase_gpuprops_get_props(base_gpu_props * const gpu_props, struct kbase_device *kbdev)
static int kbase_gpuprops_get_props(struct base_gpu_props * const gpu_props,
struct kbase_device *kbdev)
{
struct kbase_gpuprops_regdump regdump;
int i;
int err;
KBASE_DEBUG_ASSERT(NULL != kbdev);
KBASE_DEBUG_ASSERT(NULL != gpu_props);
/* Dump relevant registers */
kbase_backend_gpuprops_get(kbdev, &regdump);
err = kbase_backend_gpuprops_get(kbdev, &regdump);
if (err)
return err;
gpu_props->raw_props.gpu_id = regdump.gpu_id;
gpu_props->raw_props.tiler_features = regdump.tiler_features;
@ -169,9 +165,12 @@ static void kbase_gpuprops_get_props(base_gpu_props * const gpu_props, struct kb
gpu_props->raw_props.thread_max_workgroup_size = regdump.thread_max_workgroup_size;
gpu_props->raw_props.thread_features = regdump.thread_features;
gpu_props->raw_props.thread_tls_alloc = regdump.thread_tls_alloc;
return 0;
}
void kbase_gpuprops_update_core_props_gpu_id(base_gpu_props * const gpu_props)
void kbase_gpuprops_update_core_props_gpu_id(
struct base_gpu_props * const gpu_props)
{
gpu_props->core_props.version_status =
KBASE_UBFX32(gpu_props->raw_props.gpu_id, 0U, 4);
@ -185,13 +184,14 @@ void kbase_gpuprops_update_core_props_gpu_id(base_gpu_props * const gpu_props)
/**
* kbase_gpuprops_calculate_props - Calculate the derived properties
* @gpu_props: The &base_gpu_props structure
* @gpu_props: The &struct 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
* Fill the &struct 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)
static void kbase_gpuprops_calculate_props(
struct base_gpu_props * const gpu_props, struct kbase_device *kbdev)
{
int i;
u32 gpu_id;
@ -247,8 +247,8 @@ static void kbase_gpuprops_calculate_props(base_gpu_props * const gpu_props, str
gpu_props->thread_props.tls_alloc =
gpu_props->raw_props.thread_tls_alloc;
/* Workaround for GPU2019HW-509. MIDHARC-2364 was wrongfully applied
* to tDUx GPUs.
/* MIDHARC-2364 was intended for tULx.
* Workaround for the incorrectly applied THREAD_FEATURES to tDUx.
*/
gpu_id = kbdev->gpu_props.props.raw_props.gpu_id;
product_id = gpu_id & GPU_ID_VERSION_PRODUCT_ID;
@ -320,15 +320,18 @@ void kbase_gpuprops_set(struct kbase_device *kbdev)
gpu_props->num_job_slots = hweight32(raw->js_present);
}
void kbase_gpuprops_set_features(struct kbase_device *kbdev)
int kbase_gpuprops_set_features(struct kbase_device *kbdev)
{
base_gpu_props *gpu_props;
struct base_gpu_props *gpu_props;
struct kbase_gpuprops_regdump regdump;
int err;
gpu_props = &kbdev->gpu_props.props;
/* Dump relevant registers */
kbase_backend_gpuprops_get_features(kbdev, &regdump);
err = kbase_backend_gpuprops_get_features(kbdev, &regdump);
if (err)
return err;
/*
* Copy the raw value from the register, later this will get turned
@ -340,6 +343,8 @@ void kbase_gpuprops_set_features(struct kbase_device *kbdev)
if (!kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_THREAD_GROUP_SPLIT))
gpu_props->thread_props.max_thread_group_split = 0;
return err;
}
/*
@ -391,15 +396,17 @@ static bool kbase_read_l2_config_from_dt(struct kbase_device * const kbdev)
return false;
}
void kbase_gpuprops_update_l2_features(struct kbase_device *kbdev)
int kbase_gpuprops_update_l2_features(struct kbase_device *kbdev)
{
int err = 0;
if (kbase_hw_has_feature(kbdev, BASE_HW_FEATURE_L2_CONFIG)) {
struct kbase_gpuprops_regdump regdump;
base_gpu_props *gpu_props = &kbdev->gpu_props.props;
struct base_gpu_props *gpu_props = &kbdev->gpu_props.props;
/* Check for L2 cache size & hash overrides */
if (!kbase_read_l2_config_from_dt(kbdev))
return;
return 0;
/* Need L2 to get powered to reflect to L2_FEATURES */
kbase_pm_context_active(kbdev);
@ -408,7 +415,9 @@ void kbase_gpuprops_update_l2_features(struct kbase_device *kbdev)
kbase_pm_wait_for_l2_powered(kbdev);
/* Dump L2_FEATURES register */
kbase_backend_gpuprops_get_l2_features(kbdev, &regdump);
err = kbase_backend_gpuprops_get_l2_features(kbdev, &regdump);
if (err)
goto idle_gpu;
dev_info(kbdev->dev, "Reflected L2_FEATURES is 0x%x\n",
regdump.l2_features);
@ -418,9 +427,12 @@ void kbase_gpuprops_update_l2_features(struct kbase_device *kbdev)
gpu_props->l2_props.log2_cache_size =
KBASE_UBFX32(gpu_props->raw_props.l2_features, 16U, 8);
idle_gpu:
/* Let GPU idle */
kbase_pm_context_idle(kbdev);
}
return err;
}
static struct {
@ -600,3 +612,25 @@ int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev)
return 0;
}
void kbase_gpuprops_free_user_buffer(struct kbase_device *kbdev)
{
kfree(kbdev->gpu_props.prop_buffer);
}
int kbase_device_populate_max_freq(struct kbase_device *kbdev)
{
struct mali_base_gpu_core_props *core_props;
/* obtain max configured gpu frequency, if devfreq is enabled then
* this will be overridden by the highest operating point found
*/
core_props = &(kbdev->gpu_props.props.core_props);
#ifdef GPU_FREQ_KHZ_MAX
core_props->gpu_freq_khz_max = GPU_FREQ_KHZ_MAX;
#else
core_props->gpu_freq_khz_max = DEFAULT_GPU_FREQ_KHZ_MAX;
#endif
return 0;
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2015,2017,2019 ARM Limited. All rights reserved.
* (C) COPYRIGHT ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -18,6 +18,20 @@
*
* SPDX-License-Identifier: GPL-2.0
*
*//* SPDX-License-Identifier: GPL-2.0 */
/*
*
* (C) COPYRIGHT 2011-2015, 2017, 2019-2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
@ -35,6 +49,20 @@
/* Forward definition - see mali_kbase.h */
struct kbase_device;
/**
* 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))
/**
* @brief Set up Kbase GPU properties.
*
@ -51,26 +79,48 @@ void kbase_gpuprops_set(struct kbase_device *kbdev);
* This function sets up GPU properties that are dependent on the hardware
* features bitmask. This function must be preceeded by a call to
* kbase_hw_set_features_mask().
*
* Return: Zero on success, Linux error code on failure
*/
void kbase_gpuprops_set_features(struct kbase_device *kbdev);
int kbase_gpuprops_set_features(struct kbase_device *kbdev);
/**
* kbase_gpuprops_update_l2_features - Update GPU property of L2_FEATURES
* @kbdev: Device pointer
*
* This function updates l2_features and the log2 cache size.
*
* Return: Zero on success, Linux error code for failure
*/
void kbase_gpuprops_update_l2_features(struct kbase_device *kbdev);
int kbase_gpuprops_update_l2_features(struct kbase_device *kbdev);
/**
* kbase_gpuprops_populate_user_buffer - Populate the GPU properties buffer
* @kbdev: The kbase device
*
* Fills kbdev->gpu_props->prop_buffer with the GPU properties for user
* space to read.
* Fills prop_buffer with the GPU properties for user space to read.
*/
int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev);
/**
* kbase_gpuprops_free_user_buffer - Free the GPU properties buffer.
* @kbdev: kbase device pointer
*
* Free the GPU properties buffer allocated from
* kbase_gpuprops_populate_user_buffer.
*/
void kbase_gpuprops_free_user_buffer(struct kbase_device *kbdev);
/**
* kbase_device_populate_max_freq - Populate max gpu frequency.
* @kbdev: kbase device pointer
*
* Populate the maximum gpu frequency to be used when devfreq is disabled.
*
* Return: 0 on success and non-zero value on failure.
*/
int kbase_device_populate_max_freq(struct kbase_device *kbdev);
/**
* kbase_gpuprops_update_core_props_gpu_id - break down gpu id value
* @gpu_props: the &base_gpu_props structure
@ -79,7 +129,7 @@ int kbase_gpuprops_populate_user_buffer(struct kbase_device *kbdev);
* separate fields (version_status, minor_revision, major_revision, product_id)
* stored in base_gpu_props::core_props.
*/
void kbase_gpuprops_update_core_props_gpu_id(base_gpu_props * const gpu_props);
void kbase_gpuprops_update_core_props_gpu_id(
struct base_gpu_props * const gpu_props);
#endif /* _KBASE_GPUPROPS_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2018 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2018, 2020 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -89,7 +89,7 @@ struct kbase_gpu_props {
struct kbase_gpu_mmu_props mmu;
/* Properties shared with userspace */
base_gpu_props props;
struct base_gpu_props props;
u32 prop_buffer_size;
void *prop_buffer;

Some files were not shown because too many files have changed in this diff Show More