MALI: rockchip: upgrade midgard DDK to r12p0-04rel0

Signed-off-by: chenzhen <chenzhen@rock-chips.com>

Conflicts:

	drivers/gpu/arm/midgard/mali_kbase_core_linux.c

Change-Id: I17d67d066f6e029c2d8f1711002c347002a48399
Signed-off-by: chenzhen <chenzhen@rock-chips.com>
This commit is contained in:
chenzhen 2016-06-20 10:03:27 +08:00 committed by Huang, Tao
parent dbc9efa814
commit 5444e2e68b
43 changed files with 2279 additions and 405 deletions

View File

@ -15,7 +15,7 @@
# Driver version string which is returned to userspace via an ioctl
MALI_RELEASE_NAME ?= "r11p0-00rel0"
MALI_RELEASE_NAME ?= "r12p0-04rel0"
# Paths required for build
KBASE_PATH = $(src)
@ -111,7 +111,8 @@ SRC := \
mali_kbase_smc.c \
mali_kbase_mem_pool.c \
mali_kbase_mem_pool_debugfs.c \
mali_kbase_tlstream.c
mali_kbase_tlstream.c \
mali_kbase_strings.c
ifeq ($(MALI_UNIT_TEST),1)
SRC += mali_kbase_tlstream_test.c
@ -121,6 +122,7 @@ ifeq ($(MALI_CUSTOMER_RELEASE),0)
SRC += mali_kbase_regs_dump_debugfs.c
endif
# Job Scheduler Policy: Completely Fair Scheduler
SRC += mali_kbase_js_policy_cfs.c
@ -198,9 +200,10 @@ obj-$(CONFIG_MALI_MIDGARD) += mali_kbase.o
# Tell the Linux build system to enable building of our .c files
mali_kbase-y := $(SRC:.c=.o)
mali_kbase-$(CONFIG_MALI_DMA_FENCE) += mali_kbase_dma_fence.o
ifneq ($(wildcard $(src)/internal/Kbuild),)
ifeq ($(MALI_CUSTOMER_RELEASE),0)
# This include may set MALI_BACKEND_PATH and CONFIG_MALI_BACKEND_REAL
include $(src)/internal/Kbuild
mali_kbase-y += $(INTERNAL:.c=.o)
endif

View File

@ -59,6 +59,15 @@ config MALI_DEVFREQ
governor, the frequency of Mali will be dynamically selected from the
available OPPs.
config MALI_DMA_FENCE
bool "DMA_BUF fence support for Mali (EXPERIMENTAL)"
depends on MALI_MIDGARD && !KDS
default n
help
Support DMA_BUF fences for Mali.
This option should only be enabled if KDS is not present and
the Linux Kernel has built in support for DMA_BUF fences.
# MALI_EXPERT configuration options

View File

@ -1,5 +1,5 @@
#
# (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
# (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
#
# This program is 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,10 +26,6 @@ ifeq ($(MALI_UNIT_TEST), 1)
EXTRA_SYMBOLS += $(KBASE_PATH_RELATIVE)/tests/internal/src/kernel_assert_module/linux/Module.symvers
endif
ifneq ($(wildcard $(CURDIR)/internal/Makefile.in),)
include $(CURDIR)/internal/Makefile.in
endif
ifeq ($(MALI_BUS_LOG), 1)
#Add bus logger symbols
EXTRA_SYMBOLS += $(BUSLOG_PATH_RELATIVE)/drivers/base/bus_logger/Module.symvers

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
*
* This program is 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,7 +33,9 @@ void kbase_reg_write(struct kbase_device *kbdev, u16 offset, u32 value,
KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
dev_dbg(kbdev->dev, "w: reg %04x val %08x", offset, value);
writel(value, kbdev->reg + offset);
if (kctx && kctx->jctx.tb)
kbase_device_trace_register_access(kctx, REG_WRITE, offset,
value);
@ -48,7 +50,9 @@ u32 kbase_reg_read(struct kbase_device *kbdev, u16 offset,
KBASE_DEBUG_ASSERT(kbdev->pm.backend.gpu_powered);
KBASE_DEBUG_ASSERT(kctx == NULL || kctx->as_nr != KBASEP_AS_NR_INVALID);
KBASE_DEBUG_ASSERT(kbdev->dev != NULL);
val = readl(kbdev->reg + offset);
dev_dbg(kbdev->dev, "r: reg %04x val %08x", offset, val);
if (kctx && kctx->jctx.tb)
kbase_device_trace_register_access(kctx, REG_READ, offset, val);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -81,7 +81,6 @@ int kbase_backend_late_init(struct kbase_device *kbdev)
if (err)
goto fail_timer;
/* Currently disabled on the prototype */
#ifdef CONFIG_MALI_DEBUG
#ifndef CONFIG_MALI_NO_MALI
if (kbasep_common_test_interrupt_handlers(kbdev) != 0) {
@ -101,12 +100,13 @@ int kbase_backend_late_init(struct kbase_device *kbdev)
return 0;
fail_job_slot:
/* Currently disabled on the prototype */
#ifdef CONFIG_MALI_DEBUG
#ifndef CONFIG_MALI_NO_MALI
fail_interrupt_test:
#endif /* !CONFIG_MALI_NO_MALI */
#endif /* CONFIG_MALI_DEBUG */
kbase_backend_timer_term(kbdev);
fail_timer:
kbase_hwaccess_pm_halt(kbdev);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -28,7 +28,6 @@
#define MMU_IRQ_TAG 1
#define GPU_IRQ_TAG 2
static void *kbase_tag(void *ptr, u32 tag)
{
return (void *)(((uintptr_t) ptr) | tag);
@ -39,9 +38,6 @@ static void *kbase_untag(void *ptr)
return (void *)(((uintptr_t) ptr) & ~3);
}
static irqreturn_t kbase_job_irq_handler(int irq, void *data)
{
unsigned long flags;
@ -151,13 +147,13 @@ static irqreturn_t kbase_gpu_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static irq_handler_t kbase_handler_table[] = {
[JOB_IRQ_TAG] = kbase_job_irq_handler,
[MMU_IRQ_TAG] = kbase_mmu_irq_handler,
[GPU_IRQ_TAG] = kbase_gpu_irq_handler,
};
#ifdef CONFIG_MALI_DEBUG
#define JOB_IRQ_HANDLER JOB_IRQ_TAG
#define MMU_IRQ_HANDLER MMU_IRQ_TAG

View File

@ -207,8 +207,6 @@ static void kbasep_job_slot_update_head_start_timestamp(
}
}
#if (defined(MALI_MIPE_ENABLED) && MALI_MIPE_ENABLED) || \
!defined(MALI_MIPE_ENABLED)
/**
* kbasep_trace_tl_nret_atom_lpu - Call nret_atom_lpu timeline tracepoint
* @kbdev: kbase device
@ -226,7 +224,6 @@ static void kbasep_trace_tl_nret_atom_lpu(struct kbase_device *kbdev, int i)
kbase_tlstream_tl_nret_atom_lpu(katom,
&kbdev->gpu_props.props.raw_props.js_features[i]);
}
#endif
void kbase_job_done(struct kbase_device *kbdev, u32 done)
{
@ -291,11 +288,8 @@ void kbase_job_done(struct kbase_device *kbdev, u32 done)
kbase_tlstream_aux_job_softstop(i);
#if (defined(MALI_MIPE_ENABLED) && MALI_MIPE_ENABLED) || \
!defined(MALI_MIPE_ENABLED)
kbasep_trace_tl_nret_atom_lpu(
kbdev, i);
#endif
/* Soft-stopped job - read the value of
* JS<n>_TAIL so that the job chain can

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2010-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
*
* This program is 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 2010-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
*
* This program is 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

@ -186,4 +186,6 @@ static const enum base_hw_feature base_hw_features_tMIx[] = {
BASE_HW_FEATURE_END
};
#endif /* _BASE_HWCONFIG_FEATURES_H_ */

View File

@ -90,6 +90,7 @@ enum base_hw_issue {
BASE_HW_ISSUE_11035,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -102,6 +103,7 @@ enum base_hw_issue {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_TMIX_7940,
BASE_HW_ISSUE_TMIX_8042,
@ -173,6 +175,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p0_15dev0[] = {
BASE_HW_ISSUE_11020,
BASE_HW_ISSUE_11035,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_3964,
GPUCORE_1619,
@ -211,6 +214,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p0_eac[] = {
BASE_HW_ISSUE_11020,
BASE_HW_ISSUE_11035,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_END
@ -245,6 +249,7 @@ static const enum base_hw_issue base_hw_issues_t60x_r0p1[] = {
BASE_HW_ISSUE_11020,
BASE_HW_ISSUE_11035,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3964,
@ -277,6 +282,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r0p1[] = {
BASE_HW_ISSUE_11035,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_END
@ -298,6 +304,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r1p0[] = {
BASE_HW_ISSUE_11024,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3964,
@ -318,6 +325,7 @@ static const enum base_hw_issue base_hw_issues_t62x_r1p1[] = {
BASE_HW_ISSUE_11012,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_END
@ -332,6 +340,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p0[] = {
BASE_HW_ISSUE_11024,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -344,6 +353,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p0[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -357,6 +367,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1[] = {
BASE_HW_ISSUE_11024,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -369,6 +380,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -380,6 +392,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1_50rel0[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -392,6 +405,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p1_50rel0[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -405,6 +419,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p2[] = {
BASE_HW_ISSUE_11024,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -417,6 +432,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p2[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -428,6 +444,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p3[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_26,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
@ -440,6 +457,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r0p3[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -451,6 +469,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r1p0[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -460,6 +479,7 @@ static const enum base_hw_issue base_hw_issues_t76x_r1p0[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -475,6 +495,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r0p0[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3964,
@ -492,6 +513,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r1p0[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3964,
@ -509,6 +531,7 @@ static const enum base_hw_issue base_hw_issues_t72x_r1p1[] = {
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11042,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3964,
@ -543,6 +566,7 @@ static const enum base_hw_issue base_hw_issues_model_t76x[] = {
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
GPUCORE_1619,
BASE_HW_ISSUE_END
@ -590,6 +614,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p1[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -599,6 +624,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p1[] = {
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -609,6 +635,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p2[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -617,6 +644,7 @@ static const enum base_hw_issue base_hw_issues_tFRx_r0p2[] = {
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -627,12 +655,14 @@ static const enum base_hw_issue base_hw_issues_tFRx_r1p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -643,12 +673,14 @@ static const enum base_hw_issue base_hw_issues_tFRx_r2p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -662,6 +694,7 @@ static const enum base_hw_issue base_hw_issues_model_tFRx[] = {
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
GPUCORE_1619,
BASE_HW_ISSUE_END
@ -673,6 +706,7 @@ static const enum base_hw_issue base_hw_issues_t86x_r0p2[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -681,6 +715,7 @@ static const enum base_hw_issue base_hw_issues_t86x_r0p2[] = {
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -691,12 +726,14 @@ static const enum base_hw_issue base_hw_issues_t86x_r1p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -707,12 +744,14 @@ static const enum base_hw_issue base_hw_issues_t86x_r2p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3966,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -725,6 +764,7 @@ static const enum base_hw_issue base_hw_issues_model_t86x[] = {
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
GPUCORE_1619,
BASE_HW_ISSUE_END
@ -736,6 +776,7 @@ static const enum base_hw_issue base_hw_issues_t83x_r0p1[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -743,6 +784,7 @@ static const enum base_hw_issue base_hw_issues_t83x_r0p1[] = {
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -753,12 +795,14 @@ static const enum base_hw_issue base_hw_issues_t83x_r1p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -773,6 +817,7 @@ static const enum base_hw_issue base_hw_issues_model_t83x[] = {
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
GPUCORE_1619,
BASE_HW_ISSUE_END
@ -784,6 +829,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -792,6 +838,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p0[] = {
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3964,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -802,6 +849,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p1[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1909,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
@ -809,6 +857,7 @@ static const enum base_hw_issue base_hw_issues_t82x_r0p1[] = {
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -819,12 +868,14 @@ static const enum base_hw_issue base_hw_issues_t82x_r1p0[] = {
BASE_HW_ISSUE_10883,
BASE_HW_ISSUE_10946,
BASE_HW_ISSUE_11051,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_1963,
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_T76X_3960,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_END
};
@ -838,6 +889,7 @@ static const enum base_hw_issue base_hw_issues_model_t82x[] = {
BASE_HW_ISSUE_T76X_3086,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3793,
BASE_HW_ISSUE_T76X_3979,
BASE_HW_ISSUE_TMIX_7891,
GPUCORE_1619,
BASE_HW_ISSUE_END
@ -847,6 +899,7 @@ static const enum base_hw_issue base_hw_issues_tMIx_r0p0_05dev0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_10682,
BASE_HW_ISSUE_10821,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_T76X_3953,
BASE_HW_ISSUE_TMIX_7891,
@ -860,6 +913,7 @@ static const enum base_hw_issue base_hw_issues_tMIx_r0p0[] = {
BASE_HW_ISSUE_9435,
BASE_HW_ISSUE_10682,
BASE_HW_ISSUE_10821,
BASE_HW_ISSUE_11054,
BASE_HW_ISSUE_T76X_3700,
BASE_HW_ISSUE_TMIX_7891,
BASE_HW_ISSUE_TMIX_7940,
@ -884,4 +938,8 @@ static const enum base_hw_issue base_hw_issues_model_tMIx[] = {
BASE_HW_ISSUE_END
};
#endif /* _BASE_HWCONFIG_ISSUES_H_ */

View File

@ -173,7 +173,10 @@ enum {
BASE_MEM_SECURE = (1U << 16), /**< Secure memory */
BASE_MEM_DONT_NEED = (1U << 17), /**< Not needed physical
memory */
BASE_MEM_IMPORT_SHARED = (1U << 18), /**< Must use shared CPU/GPU zone
(SAME_VA zone) but doesn't
require the addresses to
be the same */
};
/**
@ -181,7 +184,7 @@ enum {
*
* Must be kept in sync with the ::base_mem_alloc_flags flags
*/
#define BASE_MEM_FLAGS_NR_BITS 18
#define BASE_MEM_FLAGS_NR_BITS 19
/**
* A mask for all output bits, excluding IN/OUT bits.
@ -470,6 +473,8 @@ typedef u16 base_jd_core_req;
* If this bit is set then completion of this atom will not cause an event to
* be sent to userspace, whether successful or not; completion events will be
* deferred until an atom completes which does not have this bit set.
*
* This bit may not be used in combination with BASE_JD_REQ_EXTERNAL_RESOURCES.
*/
#define BASE_JD_REQ_EVENT_COALESCE (1U << 5)
@ -492,6 +497,8 @@ typedef u16 base_jd_core_req;
* but should instead be part of a NULL jobs inserted into the dependency tree.
* The first pre_dep object must be configured for the external resouces to use,
* the second pre_dep object can be used to create other dependencies.
*
* This bit may not be used in combination with BASE_JD_REQ_EVENT_COALESCE.
*/
#define BASE_JD_REQ_EXTERNAL_RESOURCES (1U << 8)
@ -817,6 +824,7 @@ struct base_external_resource_list {
struct base_jd_debug_copy_buffer {
u64 address;
u64 size;
struct base_external_resource extres;
};
/**

View File

@ -45,6 +45,7 @@
#include <mali_kbase_uku.h>
#include <mali_kbase_linux.h>
#include "mali_kbase_strings.h"
#include "mali_kbase_pm.h"
#include "mali_kbase_mem_lowlevel.h"
#include "mali_kbase_defs.h"
@ -146,6 +147,7 @@ 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);
void kbase_job_done(struct kbase_device *kbdev, u32 done);
@ -211,7 +213,6 @@ void kbase_device_trace_buffer_uninstall(struct kbase_context *kctx);
void kbase_os_reg_write(struct kbase_device *kbdev, u16 offset, u32 value);
u32 kbase_os_reg_read(struct kbase_device *kbdev, u16 offset);
void kbasep_as_do_poke(struct work_struct *work);
/** Returns the name associated with a Mali exception code

View File

@ -65,6 +65,8 @@ kbase_create_context(struct kbase_device *kbdev, bool is_compat)
kctx->process_mm = NULL;
atomic_set(&kctx->nonmapped_pages, 0);
kctx->slots_pullable = 0;
kctx->tgid = current->tgid;
kctx->pid = current->pid;
err = kbase_mem_pool_init(&kctx->mem_pool,
kbdev->mem_pool_max_size_default,
@ -97,10 +99,13 @@ kbase_create_context(struct kbase_device *kbdev, bool is_compat)
#ifdef CONFIG_KDS
INIT_LIST_HEAD(&kctx->waiting_kds_resource);
#endif
err = kbase_dma_fence_init(kctx);
if (err)
goto free_event;
err = kbase_mmu_init(kctx);
if (err)
goto free_event;
goto term_dma_fence;
kctx->pgd = kbase_mmu_alloc_pgd(kctx);
if (!kctx->pgd)
@ -110,8 +115,6 @@ kbase_create_context(struct kbase_device *kbdev, bool is_compat)
if (!kctx->aliasing_sink_page)
goto no_sink_page;
kctx->tgid = current->tgid;
kctx->pid = current->pid;
init_waitqueue_head(&kctx->event_queue);
kctx->cookies = KBASE_COOKIE_MASK;
@ -160,6 +163,8 @@ kbase_create_context(struct kbase_device *kbdev, bool is_compat)
kbase_gpu_vm_unlock(kctx);
free_mmu:
kbase_mmu_term(kctx);
term_dma_fence:
kbase_dma_fence_term(kctx);
free_event:
kbase_event_cleanup(kctx);
free_jd:
@ -254,6 +259,8 @@ void kbase_destroy_context(struct kbase_context *kctx)
kbase_pm_context_idle(kbdev);
kbase_dma_fence_term(kctx);
kbase_mmu_term(kctx);
pages = atomic_read(&kctx->used_pages);

View File

@ -87,9 +87,6 @@
#include <mali_kbase_config.h>
#ifdef CONFIG_MACH_MANTA
#include <plat/devs.h>
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
#include <linux/pm_opp.h>
@ -109,12 +106,9 @@ static struct kbase_exported_test_data shared_kernel_test_data;
EXPORT_SYMBOL(shared_kernel_test_data);
#endif /* MALI_UNIT_TEST */
#define KBASE_DRV_NAME "mali"
/** rk_ext : version of rk_ext on mali_ko, aka. rk_ko_ver. */
#define ROCKCHIP_VERSION (13)
static const char kbase_drv_name[] = KBASE_DRV_NAME;
static int kbase_dev_nr;
static DEFINE_MUTEX(kbase_dev_list_lock);
@ -1768,7 +1762,6 @@ u32 kbase_os_reg_read(struct kbase_device *kbdev, u16 offset)
}
#endif /* !CONFIG_MALI_NO_MALI */
/** Show callback for the @c power_policy sysfs file.
*
* This function is called to get the contents of the @c power_policy sysfs
@ -2887,7 +2880,7 @@ static ssize_t kbase_show_gpuinfo(struct device *dev,
{ .id = GPU_ID_PI_T86X, .name = "Mali-T86x" },
{ .id = GPU_ID_PI_TFRX, .name = "Mali-T88x" },
{ .id = GPU_ID2_PRODUCT_TMIX >> GPU_ID_VERSION_PRODUCT_ID_SHIFT,
.name = "Mali-TMIx" },
.name = "Mali-G71" },
};
const char *product_name = "(Unknown Mali GPU)";
struct kbase_device *kbdev;
@ -3312,6 +3305,7 @@ static void kbase_common_reg_unmap(struct kbase_device * const kbdev)
static int registers_map(struct kbase_device * const kbdev)
{
/* the first memory resource is the physical address of the GPU
* registers */
struct platform_device *pdev = to_platform_device(kbdev->dev);
@ -3479,30 +3473,6 @@ MAKE_QUIRK_ACCESSORS(mmu);
#endif /* KBASE_GPU_RESET_EN */
static int kbasep_secure_mode_seq_show(struct seq_file *m, void *p)
{
struct kbase_device *kbdev = m->private;
if (!kbdev->secure_mode_support)
seq_puts(m, "unsupported\n");
else
seq_printf(m, "%s\n", kbdev->secure_mode ? "Y" : "N");
return 0;
}
static int kbasep_secure_mode_debugfs_open(struct inode *in, struct file *file)
{
return single_open(file, kbasep_secure_mode_seq_show, in->i_private);
}
static const struct file_operations kbasep_secure_mode_debugfs_fops = {
.open = kbasep_secure_mode_debugfs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int kbase_device_debugfs_init(struct kbase_device *kbdev)
{
struct dentry *debugfs_ctx_defaults_directory;
@ -3568,10 +3538,6 @@ static int kbase_device_debugfs_init(struct kbase_device *kbdev)
kbasep_trace_timeline_debugfs_init(kbdev);
#endif /* CONFIG_MALI_TRACE_TIMELINE */
debugfs_create_file("secure_mode", S_IRUGO,
kbdev->mali_debugfs_directory, kbdev,
&kbasep_secure_mode_debugfs_fops);
return 0;
out:
@ -3650,7 +3616,6 @@ static void kbase_logging_started_cb(void *data)
}
#endif
static struct attribute *kbase_attrs[] = {
#ifdef CONFIG_MALI_DEBUG
&dev_attr_debug_command.attr,
@ -3787,7 +3752,6 @@ static int kbase_platform_device_remove(struct platform_device *pdev)
kbdev->inited_subsys &= ~inited_backend_early;
}
if (kbdev->inited_subsys & inited_power_control) {
power_control_term(kbdev);
kbdev->inited_subsys &= ~inited_power_control;
@ -3881,7 +3845,6 @@ static int kbase_platform_device_probe(struct platform_device *pdev)
}
kbdev->inited_subsys |= inited_power_control;
err = kbase_backend_early_init(kbdev);
if (err) {
dev_err(kbdev->dev, "Early backend initialization failed\n");
@ -4253,19 +4216,15 @@ static int __init kbase_driver_init(void)
if (ret)
return ret;
#ifndef CONFIG_MACH_MANTA
#ifdef CONFIG_MALI_PLATFORM_FAKE
ret = kbase_platform_fake_register();
if (ret)
return ret;
#endif
#endif
ret = platform_driver_register(&kbase_platform_driver);
#ifndef CONFIG_MACH_MANTA
#ifdef CONFIG_MALI_PLATFORM_FAKE
if (ret)
kbase_platform_fake_unregister();
#endif
#endif
return ret;
}
@ -4273,11 +4232,9 @@ static int __init kbase_driver_init(void)
static void __exit kbase_driver_exit(void)
{
platform_driver_unregister(&kbase_platform_driver);
#ifndef CONFIG_MACH_MANTA
#ifdef CONFIG_MALI_PLATFORM_FAKE
kbase_platform_fake_unregister();
#endif
#endif
}
module_init(kbase_driver_init);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -15,51 +15,71 @@
#include <linux/spinlock.h>
#include "mali_kbase_debug_job_fault.h"
#ifdef CONFIG_DEBUG_FS
static bool kbase_is_job_fault_event_pending(struct list_head *event_list)
static bool kbase_is_job_fault_event_pending(struct kbase_device *kbdev)
{
bool ret;
struct list_head *event_list = &kbdev->job_fault_event_list;
unsigned long flags;
bool ret;
ret = (!list_empty(event_list));
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
ret = !list_empty(event_list);
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
return ret;
}
static bool kbase_ctx_has_no_event_pending(
struct kbase_context *kctx, struct list_head *event_list)
static bool kbase_ctx_has_no_event_pending(struct kbase_context *kctx)
{
struct kbase_device *kbdev = kctx->kbdev;
struct list_head *event_list = &kctx->kbdev->job_fault_event_list;
struct base_job_fault_event *event;
unsigned long flags;
if (list_empty(event_list))
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
if (list_empty(event_list)) {
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
return true;
list_for_each_entry(event, event_list, head) {
if (event->katom->kctx == kctx)
return false;
}
return false;
list_for_each_entry(event, event_list, head) {
if (event->katom->kctx == kctx) {
spin_unlock_irqrestore(&kbdev->job_fault_event_lock,
flags);
return false;
}
}
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
return true;
}
/* wait until the fault happen and copy the event */
static int kbase_job_fault_event_wait(struct kbase_device *kbdev,
struct list_head *event_list,
struct base_job_fault_event *event)
{
struct list_head *event_list = &kbdev->job_fault_event_list;
struct base_job_fault_event *event_in;
unsigned long flags;
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
if (list_empty(event_list)) {
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
if (wait_event_interruptible(kbdev->job_fault_wq,
kbase_is_job_fault_event_pending(event_list)))
kbase_is_job_fault_event_pending(kbdev)))
return -ERESTARTSYS;
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
}
event_in = list_entry(event_list->next,
struct base_job_fault_event, head);
event->event_code = event_in->event_code;
event->katom = event_in->katom;
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
return 0;
}
@ -102,12 +122,16 @@ static void kbase_job_fault_resume_event_cleanup(struct kbase_context *kctx)
static void kbase_job_fault_event_cleanup(struct kbase_device *kbdev)
{
struct list_head *event_list = &kbdev->job_fault_event_list;
unsigned long flags;
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
while (!list_empty(event_list)) {
kbase_job_fault_event_dequeue(kbdev, event_list);
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
wake_up(&kbdev->job_fault_resume_wq);
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
}
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
}
static void kbase_job_fault_resume_worker(struct work_struct *data)
@ -129,8 +153,7 @@ static void kbase_job_fault_resume_worker(struct work_struct *data)
* atoms belong to the same context.
*/
wait_event(kctx->kbdev->job_fault_resume_wq,
kbase_ctx_has_no_event_pending(kctx,
&kctx->kbdev->job_fault_event_list));
kbase_ctx_has_no_event_pending(kctx));
atomic_set(&kctx->job_fault_count, 0);
kbase_jd_done_worker(&katom->work);
@ -166,9 +189,12 @@ static void kbase_job_fault_event_post(struct kbase_device *kbdev,
struct kbase_jd_atom *katom, u32 completion_code)
{
struct base_job_fault_event *event;
unsigned long flags;
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
event = kbase_job_fault_event_queue(&kbdev->job_fault_event_list,
katom, completion_code);
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
wake_up_interruptible(&kbdev->job_fault_wq);
@ -293,9 +319,10 @@ static void *debug_job_fault_start(struct seq_file *m, loff_t *pos)
*/
if (*pos == 0) {
event = kmalloc(sizeof(*event), GFP_KERNEL);
if (!event)
return NULL;
event->reg_offset = 0;
if (kbase_job_fault_event_wait(kbdev,
&kbdev->job_fault_event_list, event)) {
if (kbase_job_fault_event_wait(kbdev, event)) {
kfree(event);
return NULL;
}
@ -329,11 +356,15 @@ static void debug_job_fault_stop(struct seq_file *m, void *v)
dev_info(kbdev->dev, "debug job fault seq stop stage 1");
} else {
unsigned long flags;
spin_lock_irqsave(&kbdev->job_fault_event_lock, flags);
if (!list_empty(&kbdev->job_fault_event_list)) {
kbase_job_fault_event_dequeue(kbdev,
&kbdev->job_fault_event_list);
wake_up(&kbdev->job_fault_resume_wq);
}
spin_unlock_irqrestore(&kbdev->job_fault_event_lock, flags);
dev_info(kbdev->dev, "debug job fault seq stop stage 2");
}
@ -404,6 +435,7 @@ int kbase_debug_job_fault_dev_init(struct kbase_device *kbdev)
init_waitqueue_head(&(kbdev->job_fault_wq));
init_waitqueue_head(&(kbdev->job_fault_resume_wq));
spin_lock_init(&kbdev->job_fault_event_lock);
kbdev->job_fault_resume_workq = alloc_workqueue(
"kbase_job_fault_resume_work_queue", WQ_MEM_RECLAIM, 1);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2013-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2013-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -125,6 +125,8 @@ static int debug_mem_show(struct seq_file *m, void *v)
page = pfn_to_page(PFN_DOWN(map->alloc->pages[data->offset]));
mapping = vmap(&page, 1, VM_MAP, prot);
if (!mapping)
goto out;
for (i = 0; i < PAGE_SIZE; i += 4*sizeof(*mapping)) {
seq_printf(m, "%016llx:", i + ((map->start_pfn +
@ -160,11 +162,15 @@ static int debug_mem_open(struct inode *i, struct file *file)
int ret;
ret = seq_open(file, &ops);
if (ret)
return ret;
mem_data = kmalloc(sizeof(*mem_data), GFP_KERNEL);
if (!mem_data) {
ret = -ENOMEM;
goto out;
}
mem_data->kctx = kctx;
INIT_LIST_HEAD(&mem_data->mapping_list);
@ -184,6 +190,11 @@ static int debug_mem_open(struct inode *i, struct file *file)
continue;
mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
if (!mapping) {
ret = -ENOMEM;
kbase_gpu_vm_unlock(kctx);
goto out;
}
mapping->alloc = kbase_mem_phy_alloc_get(reg->gpu_alloc);
mapping->start_pfn = reg->start_pfn;
@ -197,6 +208,22 @@ static int debug_mem_open(struct inode *i, struct file *file)
((struct seq_file *)file->private_data)->private = mem_data;
return 0;
out:
if (mem_data) {
while (!list_empty(&mem_data->mapping_list)) {
struct debug_mem_mapping *mapping;
mapping = list_first_entry(&mem_data->mapping_list,
struct debug_mem_mapping, node);
kbase_mem_phy_alloc_put(mapping->alloc);
list_del(&mapping->node);
kfree(mapping);
}
fput(kctx_file);
}
seq_release(i, file);
return ret;
}
static int debug_mem_release(struct inode *inode, struct file *file)

View File

@ -53,6 +53,8 @@
#include "sync.h"
#endif /* CONFIG_SYNC */
#include "mali_kbase_dma_fence.h"
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#endif /* CONFIG_DEBUG_FS */
@ -350,6 +352,59 @@ struct kbase_jd_atom {
struct sync_fence *fence;
struct sync_fence_waiter sync_waiter;
#endif /* CONFIG_SYNC */
#ifdef CONFIG_MALI_DMA_FENCE
struct {
/* This points to the dma-buf fence for this atom. If this is
* NULL then there is no fence for this atom and the other
* 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).
*/
struct fence *fence;
/* 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_DMA_FENCE */
/* 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;
@ -799,10 +854,12 @@ struct kbase_device {
u64 reg_start;
size_t reg_size;
void __iomem *reg;
struct {
int irq;
int flags;
} irqs[3];
struct clk *clock;
#ifdef CONFIG_REGULATOR
struct regulator *regulator;
@ -817,7 +874,7 @@ struct kbase_device {
atomic_t serving_gpu_irq;
atomic_t serving_mmu_irq;
spinlock_t reg_op_lock;
#endif /* CONFIG_MALI_NO_MALI */
#endif /* CONFIG_MALI_NO_MALI */
struct kbase_pm_device_data pm;
struct kbasep_js_device_data js_data;
@ -982,6 +1039,7 @@ struct kbase_device {
wait_queue_head_t job_fault_resume_wq;
struct workqueue_struct *job_fault_resume_workq;
struct list_head job_fault_event_list;
spinlock_t job_fault_event_lock;
struct kbase_context *kctx_fault;
#if !MALI_CUSTOMER_RELEASE
@ -1203,6 +1261,12 @@ struct kbase_context {
#ifdef CONFIG_KDS
struct list_head waiting_kds_resource;
#endif
#ifdef CONFIG_MALI_DMA_FENCE
struct {
struct list_head waiting_resource;
struct workqueue_struct *wq;
} dma_fence;
#endif /* CONFIG_MALI_DMA_FENCE */
/** This is effectively part of the Run Pool, because it only has a valid
* setting (!=KBASEP_AS_NR_INVALID) whilst the context is scheduled in
*
@ -1318,8 +1382,6 @@ struct kbase_context {
* which is mapped.
* @gpu_addr: The GPU virtual address the resource is
* mapped to.
* @refcount: Refcount to keep track of the number of
* active mappings.
*
* External resources can be mapped into multiple contexts as well as the same
* context multiple times.
@ -1327,7 +1389,7 @@ struct kbase_context {
* information to it as it could be removed under our feet leaving external
* resources pinned.
* This metadata structure binds a single external resource to a single
* context, ensuring that per context refcount is tracked separately so it can
* context, ensuring that per context mapping is tracked separately so it can
* be overridden when needed and abuses by the application (freeing the resource
* multiple times) don't effect the refcount of the physical allocation.
*/
@ -1335,7 +1397,6 @@ struct kbase_ctx_ext_res_meta {
struct list_head ext_res_node;
struct kbase_mem_phy_alloc *alloc;
u64 gpu_addr;
u64 refcount;
};
enum kbase_reg_access_type {

View File

@ -0,0 +1,524 @@
/*
*
* (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
/* Include mali_kbase_dma_fence.h before checking for CONFIG_MALI_DMA_FENCE as
* it will be set there.
*/
#include "mali_kbase_dma_fence.h"
#include <linux/atomic.h>
#include <linux/fence.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/mutex.h>
#include <linux/reservation.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/ww_mutex.h>
#include <mali_kbase.h>
/* Spin lock protecting all Mali fences as fence->lock. */
static DEFINE_SPINLOCK(kbase_dma_fence_lock);
static void
kbase_dma_fence_waiters_add(struct kbase_jd_atom *katom)
{
struct kbase_context *kctx = katom->kctx;
list_add_tail(&katom->queue, &kctx->dma_fence.waiting_resource);
}
void
kbase_dma_fence_waiters_remove(struct kbase_jd_atom *katom)
{
list_del(&katom->queue);
}
static const char *
kbase_dma_fence_get_driver_name(struct fence *fence)
{
return kbase_drv_name;
}
static const char *
kbase_dma_fence_get_timeline_name(struct fence *fence)
{
return kbase_timeline_name;
}
static bool
kbase_dma_fence_enable_signaling(struct fence *fence)
{
/* If in the future we need to add code here remember to
* to get a reference to the fence and release it when signaling
* as stated in fence.h
*/
return true;
}
static void
kbase_dma_fence_fence_value_str(struct fence *fence, char *str, int size)
{
snprintf(str, size, "%u", fence->seqno);
}
static const struct fence_ops kbase_dma_fence_ops = {
.get_driver_name = kbase_dma_fence_get_driver_name,
.get_timeline_name = kbase_dma_fence_get_timeline_name,
.enable_signaling = kbase_dma_fence_enable_signaling,
/* Use the default wait */
.wait = fence_default_wait,
.fence_value_str = kbase_dma_fence_fence_value_str,
};
static struct fence *
kbase_dma_fence_new(unsigned int context, unsigned int seqno)
{
struct fence *fence;
fence = kzalloc(sizeof(*fence), GFP_KERNEL);
if (!fence)
return NULL;
fence_init(fence,
&kbase_dma_fence_ops,
&kbase_dma_fence_lock,
context,
seqno);
return fence;
}
static int
kbase_dma_fence_lock_reservations(struct kbase_dma_fence_resv_info *info,
struct ww_acquire_ctx *ctx)
{
struct reservation_object *content_res = NULL;
unsigned int content_res_idx = 0;
unsigned int r;
int err;
ww_acquire_init(ctx, &reservation_ww_class);
retry:
for (r = 0; r < info->dma_fence_resv_count; r++) {
if (info->resv_objs[r] == content_res) {
content_res = NULL;
continue;
}
err = ww_mutex_lock(&info->resv_objs[r]->lock, ctx);
if (err)
goto error;
}
ww_acquire_done(ctx);
return err;
error:
content_res_idx = r;
/* Unlock the locked one ones */
for (r--; r >= 0; r--)
ww_mutex_unlock(&info->resv_objs[r]->lock);
if (content_res)
ww_mutex_unlock(&content_res->lock);
/* If we deadlock try with lock_slow and retry */
if (err == -EDEADLK) {
content_res = info->resv_objs[content_res_idx];
ww_mutex_lock_slow(&content_res->lock, ctx);
goto retry;
}
/* If we are here the function failed */
ww_acquire_fini(ctx);
return err;
}
static void
kbase_dma_fence_unlock_reservations(struct kbase_dma_fence_resv_info *info,
struct ww_acquire_ctx *ctx)
{
unsigned int r;
for (r = 0; r < info->dma_fence_resv_count; r++)
ww_mutex_unlock(&info->resv_objs[r]->lock);
ww_acquire_fini(ctx);
}
/**
* kbase_dma_fence_free_callbacks - Free dma-fence callbacks on a katom
* @katom: Pointer to katom
*
* This function will free all fence callbacks on the katom's list of
* callbacks. Callbacks that have not yet been called, because their fence
* hasn't yet signaled, will first be removed from the fence.
*
* Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
*/
static void
kbase_dma_fence_free_callbacks(struct kbase_jd_atom *katom)
{
struct kbase_dma_fence_cb *cb, *tmp;
lockdep_assert_held(&katom->kctx->jctx.lock);
/* Clean up and free callbacks. */
list_for_each_entry_safe(cb, tmp, &katom->dma_fence.callbacks, node) {
bool ret;
/* Cancel callbacks that hasn't been called yet. */
ret = fence_remove_callback(cb->fence, &cb->fence_cb);
if (ret) {
/* Fence had not signaled, clean up after
* canceling.
*/
atomic_dec(&katom->dma_fence.dep_count);
}
fence_put(cb->fence);
list_del(&cb->node);
kfree(cb);
}
}
/**
* kbase_dma_fence_cancel_atom() - Cancels waiting on an atom
* @katom: Katom to cancel
*
* Locking: katom->dma_fence.callbacks list assumes jctx.lock is held.
*/
static void
kbase_dma_fence_cancel_atom(struct kbase_jd_atom *katom)
{
lockdep_assert_held(&katom->kctx->jctx.lock);
/* Cancel callbacks and clean up. */
kbase_dma_fence_free_callbacks(katom);
KBASE_DEBUG_ASSERT(atomic_read(&katom->dma_fence.dep_count) == 0);
/* Mark the atom as handled in case all fences signaled just before
* canceling the callbacks and the worker was queued.
*/
atomic_set(&katom->dma_fence.dep_count, -1);
/* Prevent job_done_nolock from being called twice on an atom when
* there is a race between job completion and cancellation.
*/
if (katom->status == KBASE_JD_ATOM_STATE_QUEUED) {
/* Wait was cancelled - zap the atom */
katom->event_code = BASE_JD_EVENT_JOB_CANCELLED;
if (jd_done_nolock(katom, NULL))
kbase_js_sched_all(katom->kctx->kbdev);
}
}
/**
* kbase_dma_fence_work() - Worker thread called when a fence is signaled
* @pwork: work_struct containing a pointer to a katom
*
* This function will clean and mark all dependencies as satisfied
*/
static void
kbase_dma_fence_work(struct work_struct *pwork)
{
struct kbase_jd_atom *katom;
struct kbase_jd_context *ctx;
katom = container_of(pwork, struct kbase_jd_atom, work);
ctx = &katom->kctx->jctx;
mutex_lock(&ctx->lock);
if (atomic_read(&katom->dma_fence.dep_count) != 0)
goto out;
atomic_set(&katom->dma_fence.dep_count, -1);
/* Remove atom from list of dma-fence waiting atoms. */
kbase_dma_fence_waiters_remove(katom);
/* Cleanup callbacks. */
kbase_dma_fence_free_callbacks(katom);
/* Queue atom on GPU. */
kbase_jd_dep_clear_locked(katom);
out:
mutex_unlock(&ctx->lock);
}
static int
kbase_dma_fence_add_callback(struct kbase_jd_atom *katom,
struct fence *fence,
fence_func_t callback)
{
int err = 0;
struct kbase_dma_fence_cb *kbase_fence_cb;
kbase_fence_cb = kmalloc(sizeof(*kbase_fence_cb), GFP_KERNEL);
if (!kbase_fence_cb)
return -ENOMEM;
fence_get(fence);
kbase_fence_cb->fence = fence;
kbase_fence_cb->katom = katom;
INIT_LIST_HEAD(&kbase_fence_cb->node);
err = fence_add_callback(fence, &kbase_fence_cb->fence_cb, callback);
if (err == -ENOENT) {
/* Fence signaled, clear the error and return */
err = 0;
kbase_fence_cb->fence = NULL;
fence_put(fence);
kfree(kbase_fence_cb);
} else if (err) {
/* Do nothing, just return the error */
fence_put(fence);
kfree(kbase_fence_cb);
} else {
atomic_inc(&katom->dma_fence.dep_count);
/* Add callback to katom's list of callbacks */
list_add(&katom->dma_fence.callbacks, &kbase_fence_cb->node);
}
return err;
}
static void
kbase_dma_fence_cb(struct fence *fence, struct fence_cb *cb)
{
struct kbase_dma_fence_cb *kcb = container_of(cb,
struct kbase_dma_fence_cb,
fence_cb);
struct kbase_jd_atom *katom = kcb->katom;
struct kbase_context *kctx = katom->kctx;
/* If the atom is zapped dep_count will be forced to a negative number
* preventing this callback from ever scheduling work. Which in turn
* would reschedule the atom.
*/
if (atomic_dec_and_test(&katom->dma_fence.dep_count)) {
bool ret;
INIT_WORK(&katom->work, kbase_dma_fence_work);
ret = queue_work(kctx->dma_fence.wq, &katom->work);
/* Warn if work was already queued, that should not happen. */
WARN_ON(!ret);
}
}
static int
kbase_dma_fence_add_reservation_callback(struct kbase_jd_atom *katom,
struct reservation_object *resv,
bool exclusive)
{
struct fence *excl_fence = NULL;
struct fence **shared_fences = NULL;
unsigned int shared_count = 0;
int err, i;
err = reservation_object_get_fences_rcu(resv,
&excl_fence,
&shared_count,
&shared_fences);
if (err)
return err;
if (excl_fence) {
err = kbase_dma_fence_add_callback(katom,
excl_fence,
kbase_dma_fence_cb);
if (err)
goto error;
}
if (exclusive) {
for (i = 0; i < shared_count; i++) {
err = kbase_dma_fence_add_callback(katom,
shared_fences[i],
kbase_dma_fence_cb);
if (err)
goto error;
}
}
kfree(shared_fences);
return err;
error:
/* Cancel and clean up all callbacks that was set up before the error.
*/
kbase_dma_fence_free_callbacks(katom);
kfree(shared_fences);
return err;
}
void kbase_dma_fence_add_reservation(struct reservation_object *resv,
struct kbase_dma_fence_resv_info *info,
bool exclusive)
{
unsigned int i;
for (i = 0; i < info->dma_fence_resv_count; i++) {
/* Duplicate resource, ignore */
if (info->resv_objs[i] == resv)
return;
}
info->resv_objs[info->dma_fence_resv_count] = resv;
if (exclusive)
set_bit(info->dma_fence_resv_count,
info->dma_fence_excl_bitmap);
(info->dma_fence_resv_count)++;
}
int kbase_dma_fence_wait(struct kbase_jd_atom *katom,
struct kbase_dma_fence_resv_info *info)
{
int err, i;
struct fence *fence;
struct ww_acquire_ctx ww_ctx;
lockdep_assert_held(&katom->kctx->jctx.lock);
atomic_set(&katom->dma_fence.dep_count, 1);
fence = kbase_dma_fence_new(katom->dma_fence.context,
atomic_inc_return(&katom->dma_fence.seqno));
if (!fence) {
err = -ENOMEM;
dev_err(katom->kctx->kbdev->dev,
"Error %d creating fence.\n", err);
return err;
}
katom->dma_fence.fence = fence;
err = kbase_dma_fence_lock_reservations(info, &ww_ctx);
if (err) {
dev_err(katom->kctx->kbdev->dev,
"Error %d locking reservations.\n", err);
return err;
}
for (i = 0; i < info->dma_fence_resv_count; i++) {
struct reservation_object *obj = info->resv_objs[i];
if (!test_bit(i, info->dma_fence_excl_bitmap)) {
err = reservation_object_reserve_shared(obj);
if (err) {
dev_err(katom->kctx->kbdev->dev,
"Error %d reserving space for shared fence.\n", err);
goto end;
}
err = kbase_dma_fence_add_reservation_callback(katom, obj, false);
if (err) {
dev_err(katom->kctx->kbdev->dev,
"Error %d adding reservation to callback.\n", err);
goto end;
}
reservation_object_add_shared_fence(obj, katom->dma_fence.fence);
} else {
err = kbase_dma_fence_add_reservation_callback(katom, obj, true);
if (err) {
dev_err(katom->kctx->kbdev->dev,
"Error %d adding reservation to callback.\n", err);
goto end;
}
reservation_object_add_excl_fence(obj, katom->dma_fence.fence);
}
}
end:
kbase_dma_fence_unlock_reservations(info, &ww_ctx);
if (!err) {
/* Test if the callbacks are already triggered */
if (atomic_dec_and_test(&katom->dma_fence.dep_count)) {
atomic_set(&katom->dma_fence.dep_count, -1);
kbase_dma_fence_free_callbacks(katom);
} else {
/* Add katom to the list of dma-buf fence waiting atoms
* only if it is still waiting.
*/
kbase_dma_fence_waiters_add(katom);
}
}
return err;
}
void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx)
{
struct kbase_jd_atom *katom, *katom_tmp;
list_for_each_entry_safe(katom, katom_tmp,
&kctx->dma_fence.waiting_resource, queue) {
kbase_dma_fence_waiters_remove(katom);
kbase_dma_fence_cancel_atom(katom);
}
}
void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom)
{
/* Cancel callbacks and clean up. */
kbase_dma_fence_free_callbacks(katom);
}
void kbase_dma_fence_signal(struct kbase_jd_atom *katom)
{
if (!katom->dma_fence.fence)
return;
KBASE_DEBUG_ASSERT(atomic_read(&katom->dma_fence.dep_count) == -1);
/* Signal the atom's fence. */
fence_signal(katom->dma_fence.fence);
fence_put(katom->dma_fence.fence);
katom->dma_fence.fence = NULL;
kbase_dma_fence_free_callbacks(katom);
}
void kbase_dma_fence_term(struct kbase_context *kctx)
{
destroy_workqueue(kctx->dma_fence.wq);
kctx->dma_fence.wq = NULL;
}
int kbase_dma_fence_init(struct kbase_context *kctx)
{
INIT_LIST_HEAD(&kctx->dma_fence.waiting_resource);
kctx->dma_fence.wq = alloc_workqueue("mali-fence-%d",
WQ_UNBOUND, 1, kctx->pid);
if (!kctx->dma_fence.wq)
return -ENOMEM;
return 0;
}

View File

@ -0,0 +1,150 @@
/*
*
* (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef _KBASE_DMA_FENCE_H_
#define _KBASE_DMA_FENCE_H_
#ifdef CONFIG_MALI_DMA_FENCE
#include <linux/fence.h>
#include <linux/list.h>
#include <linux/reservation.h>
/* Forward declaration from mali_kbase_defs.h */
struct kbase_jd_atom;
struct kbase_context;
/**
* struct kbase_dma_fence_cb - Mali dma-fence callback data struct
* @fence_cb: Callback function
* @katom: Pointer to katom that is waiting on this callback
* @fence: Pointer to the fence object on which this callback is waiting
* @node: List head for linking this callback to the katom
*/
struct kbase_dma_fence_cb {
struct fence_cb fence_cb;
struct kbase_jd_atom *katom;
struct fence *fence;
struct list_head node;
};
/**
* struct kbase_dma_fence_resv_info - Structure with list of reservation objects
* @resv_objs: Array of reservation objects to attach the
* new fence to.
* @dma_fence_resv_count: Number of reservation objects in the array.
* @dma_fence_excl_bitmap: Specifies which resv_obj are exclusive.
*
* This is used by some functions to pass around a collection of data about
* reservation objects.
*/
struct kbase_dma_fence_resv_info {
struct reservation_object **resv_objs;
unsigned int dma_fence_resv_count;
unsigned long *dma_fence_excl_bitmap;
};
/**
* kbase_dma_fence_add_reservation() - Adds a resv to the array of resv_objs
* @resv: Reservation object to add to the array.
* @info: Pointer to struct with current reservation info
* @exclusive: Boolean indicating if exclusive access is needed
*
* The function adds a new reservation_object to an existing array of
* reservation_objects. At the same time keeps track of which objects require
* exclusive access in dma_fence_excl_bitmap.
*/
void kbase_dma_fence_add_reservation(struct reservation_object *resv,
struct kbase_dma_fence_resv_info *info,
bool exclusive);
/**
* kbase_dma_fence_wait() - Creates a new fence and attaches it to the resv_objs
* @katom: Katom with the external dependency.
* @info: Pointer to struct with current reservation info
*
* Return: An error code or 0 if succeeds
*/
int kbase_dma_fence_wait(struct kbase_jd_atom *katom,
struct kbase_dma_fence_resv_info *info);
/**
* kbase_dma_fence_cancel_ctx() - Cancel all dma-fences blocked atoms on kctx
* @kctx: Pointer to kbase context
*
* This function will cancel and clean up all katoms on @kctx that is waiting
* on dma-buf fences.
*
* Locking: jctx.lock needs to be held when calling this function.
*/
void kbase_dma_fence_cancel_all_atoms(struct kbase_context *kctx);
/**
* kbase_dma_fence_cancel_callbacks() - Cancel only callbacks on katom
* @katom: Pointer to katom whose callbacks are to be canceled
*
* This function cancels all dma-buf fence callbacks on @katom, but does not
* cancel the katom itself.
*
* The caller is responsible for ensuring that jd_done_nolock is called on
* @katom.
*
* Locking: jctx.lock must be held when calling this function.
*/
void kbase_dma_fence_cancel_callbacks(struct kbase_jd_atom *katom);
/**
* kbase_dma_fence_signal() - Signal katom's fence and clean up after wait
* @katom: Pointer to katom to signal and clean up
*
* This function will signal the @katom's fence, if it has one, and clean up
* the callback data from the katom's wait on earlier fences.
*
* Locking: jctx.lock must be held while calling this function.
*/
void kbase_dma_fence_signal(struct kbase_jd_atom *katom);
/**
* kbase_dma_fence_term() - Terminate Mali dma-fence context
* @kctx: kbase context to terminate
*/
void kbase_dma_fence_term(struct kbase_context *kctx);
/**
* kbase_dma_fence_init() - Initialize Mali dma-fence context
* @kctx: kbase context to initialize
*/
int kbase_dma_fence_init(struct kbase_context *kctx);
/**
* kbase_dma_fence_waiters_remove()- Remove katom from dma-fence wait list
* @katom: Pointer to katom to remove from list
*/
void kbase_dma_fence_waiters_remove(struct kbase_jd_atom *katom);
#else /* CONFIG_MALI_DMA_FENCE */
/* Dummy functions for when dma-buf fence isn't enabled. */
static inline int kbase_dma_fence_init(struct kbase_context *kctx)
{
return 0;
}
static inline void kbase_dma_fence_term(struct kbase_context *kctx) {}
#endif /* CONFIG_MALI_DMA_FENCE */
#endif

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -28,18 +28,23 @@
#define MALI_BYTES_PER_COUNTER 4
struct kbase_gator_hwcnt_handles {
struct kbase_device *kbdev;
struct kbase_context *kctx;
u64 hwcnt_gpu_va;
void *hwcnt_cpu_va;
struct kbase_vmap_struct hwcnt_map;
struct kbase_device *kbdev;
struct kbase_vinstr_client *vinstr_cli;
void *vinstr_buffer;
struct work_struct dump_work;
int dump_complete;
spinlock_t dump_lock;
};
static void dump_worker(struct work_struct *work);
const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters)
{
uint32_t gpu_id;
const char * const *hardware_counters;
struct kbase_device *kbdev;
uint32_t gpu_id;
uint32_t product_id;
uint32_t count;
if (!total_counters)
return NULL;
@ -50,58 +55,78 @@ const char * const *kbase_gator_hwcnt_init_names(uint32_t *total_counters)
return NULL;
gpu_id = kbdev->gpu_props.props.core_props.product_id;
product_id = gpu_id & GPU_ID_VERSION_PRODUCT_ID;
product_id >>= GPU_ID_VERSION_PRODUCT_ID_SHIFT;
switch (gpu_id) {
/* If we are using a Mali-T60x device */
case GPU_ID_PI_T60X:
hardware_counters = hardware_counters_mali_t60x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t60x);
break;
/* If we are using a Mali-T62x device */
case GPU_ID_PI_T62X:
hardware_counters = hardware_counters_mali_t62x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t62x);
break;
/* If we are using a Mali-T72x device */
case GPU_ID_PI_T72X:
hardware_counters = hardware_counters_mali_t72x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t72x);
break;
/* If we are using a Mali-T76x device */
case GPU_ID_PI_T76X:
hardware_counters = hardware_counters_mali_t76x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t76x);
break;
/* If we are using a Mali-T82x device */
case GPU_ID_PI_T82X:
hardware_counters = hardware_counters_mali_t82x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t82x);
break;
/* If we are using a Mali-T83x device */
case GPU_ID_PI_T83X:
hardware_counters = hardware_counters_mali_t83x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t83x);
break;
/* If we are using a Mali-T86x device */
case GPU_ID_PI_T86X:
hardware_counters = hardware_counters_mali_t86x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t86x);
break;
/* If we are using a Mali-T88x device */
case GPU_ID_PI_TFRX:
hardware_counters = hardware_counters_mali_t88x;
*total_counters = ARRAY_SIZE(hardware_counters_mali_t88x);
break;
default:
hardware_counters = NULL;
*total_counters = 0;
dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n", gpu_id);
break;
if (GPU_ID_IS_NEW_FORMAT(product_id)) {
switch (gpu_id & GPU_ID2_PRODUCT_MODEL) {
case GPU_ID2_PRODUCT_TMIX:
hardware_counters = hardware_counters_mali_tMIx;
count = ARRAY_SIZE(hardware_counters_mali_tMIx);
break;
default:
hardware_counters = NULL;
count = 0;
dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
gpu_id);
break;
}
} else {
switch (gpu_id) {
/* If we are using a Mali-T60x device */
case GPU_ID_PI_T60X:
hardware_counters = hardware_counters_mali_t60x;
count = ARRAY_SIZE(hardware_counters_mali_t60x);
break;
/* If we are using a Mali-T62x device */
case GPU_ID_PI_T62X:
hardware_counters = hardware_counters_mali_t62x;
count = ARRAY_SIZE(hardware_counters_mali_t62x);
break;
/* If we are using a Mali-T72x device */
case GPU_ID_PI_T72X:
hardware_counters = hardware_counters_mali_t72x;
count = ARRAY_SIZE(hardware_counters_mali_t72x);
break;
/* If we are using a Mali-T76x device */
case GPU_ID_PI_T76X:
hardware_counters = hardware_counters_mali_t76x;
count = ARRAY_SIZE(hardware_counters_mali_t76x);
break;
/* If we are using a Mali-T82x device */
case GPU_ID_PI_T82X:
hardware_counters = hardware_counters_mali_t82x;
count = ARRAY_SIZE(hardware_counters_mali_t82x);
break;
/* If we are using a Mali-T83x device */
case GPU_ID_PI_T83X:
hardware_counters = hardware_counters_mali_t83x;
count = ARRAY_SIZE(hardware_counters_mali_t83x);
break;
/* If we are using a Mali-T86x device */
case GPU_ID_PI_T86X:
hardware_counters = hardware_counters_mali_t86x;
count = ARRAY_SIZE(hardware_counters_mali_t86x);
break;
/* If we are using a Mali-T88x device */
case GPU_ID_PI_TFRX:
hardware_counters = hardware_counters_mali_t88x;
count = ARRAY_SIZE(hardware_counters_mali_t88x);
break;
default:
hardware_counters = NULL;
count = 0;
dev_err(kbdev->dev, "Unrecognized gpu ID: %u\n",
gpu_id);
break;
}
}
/* Release the kbdev reference. */
kbase_release_device(kbdev);
*total_counters = count;
/* If we return a string array take a reference on the module (or fail). */
if (hardware_counters && !try_module_get(THIS_MODULE))
return NULL;
@ -120,13 +145,8 @@ KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term_names);
struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcnt_info *in_out_info)
{
struct kbase_gator_hwcnt_handles *hand;
struct kbase_uk_hwcnt_setup setup;
int err;
struct kbase_uk_hwcnt_reader_setup setup;
uint32_t dump_size = 0, i = 0;
struct kbase_va_region *reg;
u64 flags;
u64 nr_pages;
u16 va_alignment = 0;
if (!in_out_info)
return NULL;
@ -135,15 +155,19 @@ struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcn
if (!hand)
return NULL;
INIT_WORK(&hand->dump_work, dump_worker);
spin_lock_init(&hand->dump_lock);
/* Get the first device */
hand->kbdev = kbase_find_device(-1);
if (!hand->kbdev)
goto free_hand;
/* Create a kbase_context */
hand->kctx = kbase_create_context(hand->kbdev, true);
if (!hand->kctx)
dump_size = kbase_vinstr_dump_size(hand->kbdev);
hand->vinstr_buffer = kzalloc(dump_size, GFP_KERNEL);
if (!hand->vinstr_buffer)
goto release_device;
in_out_info->kernel_dump_buffer = hand->vinstr_buffer;
in_out_info->nr_cores = hand->kbdev->gpu_props.num_cores;
in_out_info->nr_core_groups = hand->kbdev->gpu_props.num_core_groups;
@ -160,7 +184,7 @@ struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcn
in_out_info->nr_core_groups, GFP_KERNEL);
if (!in_out_info->hwc_layout)
goto destroy_context;
goto free_vinstr_buffer;
dump_size = in_out_info->nr_core_groups *
MALI_MAX_NUM_BLOCKS_PER_GROUP *
@ -203,7 +227,7 @@ struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcn
in_out_info->hwc_layout = kmalloc(sizeof(enum hwc_type) * (2 + nr_sc_bits + nr_l2), GFP_KERNEL);
if (!in_out_info->hwc_layout)
goto destroy_context;
goto free_vinstr_buffer;
dump_size = (2 + nr_sc_bits + nr_l2) * MALI_COUNTERS_PER_BLOCK * MALI_BYTES_PER_COUNTER;
@ -223,58 +247,32 @@ struct kbase_gator_hwcnt_handles *kbase_gator_hwcnt_init(struct kbase_gator_hwcn
}
in_out_info->nr_hwc_blocks = i;
in_out_info->size = dump_size;
flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_CPU_WR | BASE_MEM_PROT_GPU_WR;
nr_pages = PFN_UP(dump_size);
reg = kbase_mem_alloc(hand->kctx, nr_pages, nr_pages, 0,
&flags, &hand->hwcnt_gpu_va, &va_alignment);
if (!reg)
goto free_layout;
hand->hwcnt_cpu_va = kbase_vmap(hand->kctx, hand->hwcnt_gpu_va,
dump_size, &hand->hwcnt_map);
if (!hand->hwcnt_cpu_va)
goto free_buffer;
in_out_info->kernel_dump_buffer = hand->hwcnt_cpu_va;
memset(in_out_info->kernel_dump_buffer, 0, nr_pages * PAGE_SIZE);
/*setup.dump_buffer = (uintptr_t)in_out_info->kernel_dump_buffer;*/
setup.dump_buffer = hand->hwcnt_gpu_va;
setup.jm_bm = in_out_info->bitmask[0];
setup.tiler_bm = in_out_info->bitmask[1];
setup.shader_bm = in_out_info->bitmask[2];
setup.mmu_l2_bm = in_out_info->bitmask[3];
err = kbase_instr_hwcnt_enable(hand->kctx, &setup);
if (err)
goto free_unmap;
kbase_instr_hwcnt_clear(hand->kctx);
hand->vinstr_cli = kbase_vinstr_hwcnt_kernel_setup(hand->kbdev->vinstr_ctx,
&setup, hand->vinstr_buffer);
if (!hand->vinstr_cli) {
dev_err(hand->kbdev->dev, "Failed to register gator with vinstr core");
goto free_layout;
}
return hand;
free_unmap:
kbase_vunmap(hand->kctx, &hand->hwcnt_map);
free_buffer:
kbase_mem_free(hand->kctx, hand->hwcnt_gpu_va);
free_layout:
kfree(in_out_info->hwc_layout);
destroy_context:
kbase_destroy_context(hand->kctx);
free_vinstr_buffer:
kfree(hand->vinstr_buffer);
release_device:
kbase_release_device(hand->kbdev);
free_hand:
kfree(hand);
return NULL;
}
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_init);
@ -285,27 +283,39 @@ void kbase_gator_hwcnt_term(struct kbase_gator_hwcnt_info *in_out_info, struct k
kfree(in_out_info->hwc_layout);
if (opaque_handles) {
kbase_instr_hwcnt_disable(opaque_handles->kctx);
kbase_vunmap(opaque_handles->kctx, &opaque_handles->hwcnt_map);
kbase_mem_free(opaque_handles->kctx, opaque_handles->hwcnt_gpu_va);
kbase_destroy_context(opaque_handles->kctx);
cancel_work_sync(&opaque_handles->dump_work);
kbase_vinstr_detach_client(opaque_handles->vinstr_cli);
kfree(opaque_handles->vinstr_buffer);
kbase_release_device(opaque_handles->kbdev);
kfree(opaque_handles);
}
}
KBASE_EXPORT_SYMBOL(kbase_gator_hwcnt_term);
static void dump_worker(struct work_struct *work)
{
struct kbase_gator_hwcnt_handles *hand;
hand = container_of(work, struct kbase_gator_hwcnt_handles, dump_work);
if (!kbase_vinstr_hwc_dump(hand->vinstr_cli,
BASE_HWCNT_READER_EVENT_MANUAL)) {
spin_lock_bh(&hand->dump_lock);
hand->dump_complete = 1;
spin_unlock_bh(&hand->dump_lock);
} else {
schedule_work(&hand->dump_work);
}
}
uint32_t kbase_gator_instr_hwcnt_dump_complete(
struct kbase_gator_hwcnt_handles *opaque_handles,
uint32_t * const success)
{
bool ret_res, success_res;
if (opaque_handles && success) {
ret_res = kbase_instr_hwcnt_dump_complete(opaque_handles->kctx,
&success_res);
*success = (uint32_t)success_res;
return (uint32_t)(ret_res != 0);
*success = opaque_handles->dump_complete;
opaque_handles->dump_complete = 0;
return *success;
}
return 0;
}
@ -314,9 +324,7 @@ KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_complete);
uint32_t kbase_gator_instr_hwcnt_dump_irq(struct kbase_gator_hwcnt_handles *opaque_handles)
{
if (opaque_handles)
return (kbase_instr_hwcnt_request_dump(
opaque_handles->kctx) == 0);
schedule_work(&opaque_handles->dump_work);
return 0;
}
KBASE_EXPORT_SYMBOL(kbase_gator_instr_hwcnt_dump_irq);

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2014-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -2156,4 +2156,8 @@ static const char * const hardware_counters_mali_t88x[] = {
"T88x_L2_REPLAY_FULL"
};
#include "mali_kbase_gator_hwcnt_names_tmix.h"
#endif

View File

@ -0,0 +1,291 @@
/*
*
* (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
/*
* This header was autogenerated, it should not be edited.
*/
#ifndef _KBASE_GATOR_HWCNT_NAMES_TMIX_H_
#define _KBASE_GATOR_HWCNT_NAMES_TMIX_H_
static const char * const hardware_counters_mali_tMIx[] = {
/* Performance counters for the Job Manager */
"",
"",
"",
"",
"TMIx_MESSAGES_SENT",
"TMIx_MESSAGES_RECEIVED",
"TMIx_GPU_ACTIVE",
"TMIx_IRQ_ACTIVE",
"TMIx_JS0_JOBS",
"TMIx_JS0_TASKS",
"TMIx_JS0_ACTIVE",
"",
"TMIx_JS0_WAIT_READ",
"TMIx_JS0_WAIT_ISSUE",
"TMIx_JS0_WAIT_DEPEND",
"TMIx_JS0_WAIT_FINISH",
"TMIx_JS1_JOBS",
"TMIx_JS1_TASKS",
"TMIx_JS1_ACTIVE",
"",
"TMIx_JS1_WAIT_READ",
"TMIx_JS1_WAIT_ISSUE",
"TMIx_JS1_WAIT_DEPEND",
"TMIx_JS1_WAIT_FINISH",
"TMIx_JS2_JOBS",
"TMIx_JS2_TASKS",
"TMIx_JS2_ACTIVE",
"",
"TMIx_JS2_WAIT_READ",
"TMIx_JS2_WAIT_ISSUE",
"TMIx_JS2_WAIT_DEPEND",
"TMIx_JS2_WAIT_FINISH",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
/* Performance counters for the Tiler */
"",
"",
"",
"",
"TMIx_TILER_ACTIVE",
"TMIx_JOBS_PROCESSED",
"TMIx_TRIANGLES",
"TMIx_LINES",
"TMIx_POINTS",
"TMIx_FRONT_FACING",
"TMIx_BACK_FACING",
"TMIx_PRIM_VISIBLE",
"TMIx_PRIM_CULLED",
"TMIx_PRIM_CLIPPED",
"TMIx_PRIM_SAT_CULLED",
"",
"",
"TMIx_BUS_READ",
"",
"TMIx_BUS_WRITE",
"TMIx_LOADING_DESC",
"TMIx_IDVS_POS_SHAD_REQ",
"TMIx_IDVS_POS_SHAD_WAIT",
"TMIx_IDVS_POS_SHAD_STALL",
"TMIx_IDVS_POS_FIFO_FULL",
"TMIx_PREFETCH_STALL",
"TMIx_VCACHE_HIT",
"TMIx_VCACHE_MISS",
"TMIx_VCACHE_LINE_WAIT",
"TMIx_VFETCH_POS_READ_WAIT",
"TMIx_VFETCH_VERTEX_WAIT",
"TMIx_VFETCH_STALL",
"TMIx_PRIMASSY_STALL",
"TMIx_BBOX_GEN_STALL",
"TMIx_IDVS_VBU_HIT",
"TMIx_IDVS_VBU_MISS",
"TMIx_IDVS_VBU_LINE_DEALLOCATE",
"TMIx_IDVS_VAR_SHAD_REQ",
"TMIx_IDVS_VAR_SHAD_STALL",
"TMIx_BINNER_STALL",
"TMIx_ITER_STALL",
"TMIx_COMPRESS_MISS",
"TMIx_COMPRESS_STALL",
"TMIx_PCACHE_HIT",
"TMIx_PCACHE_MISS",
"TMIx_PCACHE_MISS_STALL",
"TMIx_PCACHE_EVICT_STALL",
"TMIx_PMGR_PTR_WR_STALL",
"TMIx_PMGR_PTR_RD_STALL",
"TMIx_PMGR_CMD_WR_STALL",
"TMIx_WRBUF_ACTIVE",
"TMIx_WRBUF_HIT",
"TMIx_WRBUF_MISS",
"TMIx_WRBUF_NO_FREE_LINE_STALL",
"TMIx_WRBUF_NO_AXI_ID_STALL",
"TMIx_WRBUF_AXI_STALL",
"",
"",
"",
"TMIx_UTLB_TRANS",
"TMIx_UTLB_TRANS_HIT",
"TMIx_UTLB_TRANS_STALL",
"TMIx_UTLB_TRANS_MISS_DELAY",
"TMIx_UTLB_MMU_REQ",
/* Performance counters for the Shader Core */
"",
"",
"",
"",
"TMIx_FRAG_ACTIVE",
"TMIx_FRAG_PRIMITIVES",
"TMIx_FRAG_PRIM_RAST",
"TMIx_FRAG_FPK_ACTIVE",
"TMIx_FRAG_STARVING",
"TMIx_FRAG_WARPS",
"TMIx_FRAG_PARTIAL_WARPS",
"TMIx_FRAG_QUADS_RAST",
"TMIx_FRAG_QUADS_EZS_TEST",
"TMIx_FRAG_QUADS_EZS_UPDATE",
"TMIx_FRAG_QUADS_EZS_KILL",
"TMIx_FRAG_LZS_TEST",
"TMIx_FRAG_LZS_KILL",
"",
"TMIx_FRAG_PTILES",
"TMIx_FRAG_TRANS_ELIM",
"TMIx_QUAD_FPK_KILLER",
"",
"TMIx_COMPUTE_ACTIVE",
"TMIx_COMPUTE_TASKS",
"TMIx_COMPUTE_WARPS",
"TMIx_COMPUTE_STARVING",
"TMIx_EXEC_CORE_ACTIVE",
"TMIx_EXEC_ACTIVE",
"TMIx_EXEC_INSTR_COUNT",
"TMIx_EXEC_INSTR_DIVERGED",
"TMIx_EXEC_INSTR_STARVING",
"TMIx_ARITH_INSTR_SINGLE_FMA",
"TMIx_ARITH_INSTR_DOUBLE",
"TMIx_ARITH_INSTR_MSG",
"TMIx_ARITH_INSTR_MSG_ONLY",
"TMIx_TEX_INSTR",
"TMIx_TEX_INSTR_MIPMAP",
"TMIx_TEX_INSTR_COMPRESSED",
"TMIx_TEX_INSTR_3D",
"TMIx_TEX_INSTR_TRILINEAR",
"TMIx_TEX_COORD_ISSUE",
"TMIx_TEX_COORD_STALL",
"TMIx_TEX_STARVE_CACHE",
"TMIx_TEX_STARVE_FILTER",
"TMIx_LS_MEM_READ_FULL",
"TMIx_LS_MEM_READ_SHORT",
"TMIx_LS_MEM_WRITE_FULL",
"TMIx_LS_MEM_WRITE_SHORT",
"TMIx_LS_MEM_ATOMIC",
"TMIx_VARY_INSTR",
"",
"",
"TMIx_ATTR_INSTR",
"TMIx_ARITH_INSTR_FP_MUL",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
/* Performance counters for the Memory System */
"",
"",
"",
"",
"TMIx_MMU_REQUESTS",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"TMIx_L2_RD_MSG_IN",
"TMIx_L2_RD_MSG_IN_STALL",
"TMIx_L2_WR_MSG_IN",
"TMIx_L2_WR_MSG_IN_STALL",
"TMIx_L2_SNP_MSG_IN",
"TMIx_L2_SNP_MSG_IN_STALL",
"TMIx_L2_RD_MSG_OUT",
"TMIx_L2_RD_MSG_OUT_STALL",
"TMIx_L2_WR_MSG_OUT",
"TMIx_L2_ANY_LOOKUP",
"TMIx_L2_READ_LOOKUP",
"TMIx_L2_WRITE_LOOKUP",
"TMIx_L2_EXT_SNOOP_LOOKUP",
"TMIx_L2_EXT_READ",
"TMIx_L2_EXT_READ_NOSNP",
"TMIx_L2_EXT_READ_UNIQUE",
"TMIx_L2_EXT_READ_BEATS",
"TMIx_L2_EXT_AR_STALL",
"TMIx_L2_EXT_AR_CNT_Q1",
"TMIx_L2_EXT_AR_CNT_Q2",
"TMIx_L2_EXT_AR_CNT_Q3",
"",
"",
"",
"",
"",
"TMIx_L2_EXT_WRITE",
"TMIx_L2_EXT_WRITE_NOSNP_FULL",
"TMIx_L2_EXT_WRITE_NOSNP_PTL",
"TMIx_L2_EXT_WRITE_SNP_FULL",
"TMIx_L2_EXT_WRITE_SNP_PTL",
"TMIx_L2_EXT_WRITE_BEATS",
"TMIx_L2_EXT_W_STALL",
"TMIx_L2_EXT_AW_CNT_Q1",
"TMIx_L2_EXT_AW_CNT_Q2",
"TMIx_L2_EXT_AW_CNT_Q3",
"TMIx_L2_EXT_SNOOP",
"TMIx_L2_EXT_SNOOP_STALL",
"TMIx_L2_EXT_SNOOP_RESP_CLEAN",
"TMIx_L2_EXT_SNOOP_RESP_DATA",
"TMIx_L2_EXT_SNOOP_INTERNAL",
"",
"",
"",
"",
"",
"",
"",
};
#endif /* _KBASE_GATOR_HWCNT_NAMES_TMIX_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved.
*
* This program is 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

@ -34,6 +34,8 @@
#include <mali_kbase_hwaccess_jm.h>
#include <mali_kbase_tlstream.h>
#include "mali_kbase_dma_fence.h"
#define beenthere(kctx, f, a...) dev_dbg(kctx->kbdev->dev, "%s:" f, __func__, ##a)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
@ -105,6 +107,39 @@ static int jd_run_atom(struct kbase_jd_atom *katom)
return kbasep_js_add_job(kctx, katom);
}
#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE)
void kbase_jd_dep_clear_locked(struct kbase_jd_atom *katom)
{
struct kbase_device *kbdev;
KBASE_DEBUG_ASSERT(katom);
kbdev = katom->kctx->kbdev;
KBASE_DEBUG_ASSERT(kbdev);
/* Check whether the atom's other dependencies were already met. If
* katom is a GPU atom then the job scheduler may be able to represent
* the dependencies, hence we may attempt to submit it before they are
* met. Other atoms must have had both dependencies resolved.
*/
if (IS_GPU_ATOM(katom) ||
(!kbase_jd_katom_dep_atom(&katom->dep[0]) &&
!kbase_jd_katom_dep_atom(&katom->dep[1]))) {
/* katom dep complete, attempt to run it */
bool resched = false;
resched = jd_run_atom(katom);
if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) {
/* The atom has already finished */
resched |= jd_done_nolock(katom, NULL);
}
if (resched)
kbase_js_sched_all(kbdev);
}
}
#endif
#ifdef CONFIG_KDS
/* Add the katom to the kds waiting list.
@ -137,44 +172,20 @@ static void kds_dep_clear(void *callback_parameter, void *callback_extra_paramet
{
struct kbase_jd_atom *katom;
struct kbase_jd_context *ctx;
struct kbase_device *kbdev;
katom = (struct kbase_jd_atom *)callback_parameter;
KBASE_DEBUG_ASSERT(katom);
ctx = &katom->kctx->jctx;
kbdev = katom->kctx->kbdev;
KBASE_DEBUG_ASSERT(kbdev);
/* If KDS resource has already been satisfied (e.g. due to zapping)
* do nothing.
*/
mutex_lock(&ctx->lock);
/* KDS resource has already been satisfied (e.g. due to zapping) */
if (katom->kds_dep_satisfied)
goto out;
/* This atom's KDS dependency has now been met */
katom->kds_dep_satisfied = true;
/* Check whether the atom's other dependencies were already met. If
* katom is a GPU atom then the job scheduler may be able to represent
* the dependencies, hence we may attempt to submit it before they are
* met. Other atoms must have had both dependencies resolved */
if (IS_GPU_ATOM(katom) ||
(!kbase_jd_katom_dep_atom(&katom->dep[0]) &&
!kbase_jd_katom_dep_atom(&katom->dep[1]))) {
/* katom dep complete, attempt to run it */
bool resched = false;
resched = jd_run_atom(katom);
if (katom->status == KBASE_JD_ATOM_STATE_COMPLETED) {
/* The atom has already finished */
resched |= jd_done_nolock(katom, NULL);
}
if (resched)
kbase_js_sched_all(kbdev);
if (!katom->kds_dep_satisfied) {
katom->kds_dep_satisfied = true;
kbase_jd_dep_clear_locked(katom);
}
out:
mutex_unlock(&ctx->lock);
}
@ -213,6 +224,16 @@ void kbase_jd_free_external_resources(struct kbase_jd_atom *katom)
kds_resource_set_release_sync(&katom->kds_rset);
}
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
/* Flush dma-fence workqueue to ensure that any callbacks that may have
* been queued are done before continuing.
* Any successfully completed atom would have had all it's callbacks
* completed before the atom was run, so only flush for failed atoms.
*/
if (katom->event_code != BASE_JD_EVENT_DONE)
flush_workqueue(katom->kctx->dma_fence.wq);
#endif /* CONFIG_MALI_DMA_FENCE */
}
static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom)
@ -226,6 +247,10 @@ static void kbase_jd_post_external_resources(struct kbase_jd_atom *katom)
katom->kds_dep_satisfied = true;
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
kbase_dma_fence_signal(katom);
#endif /* CONFIG_MALI_DMA_FENCE */
kbase_gpu_vm_lock(katom->kctx);
/* only roll back if extres is non-NULL */
if (katom->extres) {
@ -262,6 +287,11 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st
struct kds_resource **kds_resources = NULL;
unsigned long *kds_access_bitmap = NULL;
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
struct kbase_dma_fence_resv_info info = {
.dma_fence_resv_count = 0,
};
#endif
struct base_external_resource *input_extres;
KBASE_DEBUG_ASSERT(katom);
@ -297,20 +327,39 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st
KBASE_DEBUG_ASSERT(0 != katom->nr_extres);
kds_resources = kmalloc_array(katom->nr_extres, sizeof(struct kds_resource *), GFP_KERNEL);
if (NULL == kds_resources) {
if (!kds_resources) {
err_ret_val = -ENOMEM;
goto early_err_out;
}
KBASE_DEBUG_ASSERT(0 != katom->nr_extres);
kds_access_bitmap = kzalloc(sizeof(unsigned long) * ((katom->nr_extres + BITS_PER_LONG - 1) / BITS_PER_LONG), GFP_KERNEL);
if (NULL == kds_access_bitmap) {
kds_access_bitmap = kcalloc(BITS_TO_LONGS(katom->nr_extres),
sizeof(unsigned long),
GFP_KERNEL);
if (!kds_access_bitmap) {
err_ret_val = -ENOMEM;
goto early_err_out;
}
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
info.resv_objs = kmalloc_array(katom->nr_extres,
sizeof(struct reservation_object *),
GFP_KERNEL);
if (!info.resv_objs) {
err_ret_val = -ENOMEM;
goto early_err_out;
}
info.dma_fence_excl_bitmap = kcalloc(BITS_TO_LONGS(katom->nr_extres),
sizeof(unsigned long),
GFP_KERNEL);
if (!info.dma_fence_excl_bitmap) {
err_ret_val = -ENOMEM;
goto early_err_out;
}
#endif /* CONFIG_MALI_DMA_FENCE */
/* Take the processes mmap lock */
down_read(&current->mm->mmap_sem);
@ -351,6 +400,17 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st
goto failed_loop;
}
#ifdef CONFIG_MALI_DMA_FENCE
if (reg->gpu_alloc->type == KBASE_MEM_TYPE_IMPORTED_UMM) {
struct reservation_object *resv;
resv = reg->gpu_alloc->imported.umm.dma_buf->resv;
if (resv)
kbase_dma_fence_add_reservation(resv, &info,
exclusive);
}
#endif /* CONFIG_MALI_DMA_FENCE */
/* finish with updating out array with the data we found */
/* NOTE: It is important that this is the last thing we do (or
* at least not before the first write) as we overwrite elements
@ -391,19 +451,50 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st
kfree(kds_access_bitmap);
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
if (info.dma_fence_resv_count) {
int ret;
ret = kbase_dma_fence_wait(katom, &info);
if (ret < 0)
goto failed_dma_fence_setup;
}
kfree(info.resv_objs);
kfree(info.dma_fence_excl_bitmap);
#endif /* CONFIG_MALI_DMA_FENCE */
/* all done OK */
return 0;
/* error handling section */
#ifdef CONFIG_MALI_DMA_FENCE
failed_dma_fence_setup:
#ifdef CONFIG_KDS
failed_kds_setup:
/* If we are here, dma_fence setup failed but KDS didn't.
* Revert KDS setup if any.
*/
if (kds_res_count) {
mutex_unlock(&katom->kctx->jctx.lock);
kds_resource_set_release_sync(&katom->kds_rset);
mutex_lock(&katom->kctx->jctx.lock);
kbase_jd_kds_waiters_remove(katom);
katom->kds_dep_satisfied = true;
}
#endif /* CONFIG_KDS */
#endif /* CONFIG_MALI_DMA_FENCE */
#ifdef CONFIG_KDS
failed_kds_setup:
#endif
#if defined(CONFIG_KDS) || defined(CONFIG_MALI_DMA_FENCE)
/* Lock the processes mmap lock */
down_read(&current->mm->mmap_sem);
/* lock before we unmap */
kbase_gpu_vm_lock(katom->kctx);
#endif /* CONFIG_KDS */
#endif
failed_loop:
/* undo the loop work */
@ -424,6 +515,10 @@ static int kbase_jd_pre_external_resources(struct kbase_jd_atom *katom, const st
kfree(kds_resources);
kfree(kds_access_bitmap);
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
kfree(info.resv_objs);
kfree(info.dma_fence_excl_bitmap);
#endif
return err_ret_val;
}
@ -456,6 +551,10 @@ static inline void jd_resolve_dep(struct list_head *out_list,
}
#endif
#ifdef CONFIG_MALI_DMA_FENCE
kbase_dma_fence_cancel_callbacks(dep_atom);
#endif
dep_atom->event_code = katom->event_code;
KBASE_DEBUG_ASSERT(dep_atom->status !=
KBASE_JD_ATOM_STATE_UNUSED);
@ -470,9 +569,40 @@ static inline void jd_resolve_dep(struct list_head *out_list,
}
}
if (!kbase_jd_katom_dep_atom(&dep_atom->dep[other_d])) {
bool dep_satisfied = true;
#ifdef CONFIG_MALI_DMA_FENCE
int dep_count;
dep_count = atomic_read(&dep_atom->dma_fence.dep_count);
if (likely(dep_count == -1)) {
dep_satisfied = true;
} else if (dep_count == 0) {
/*
* All fences for this atom has signaled, but
* the worker that will queue the atom has not
* yet run.
*
* Mark the atom as handled by setting
* dep_count to -1 so that the worker doesn't
* queue the atom again.
*/
atomic_set(&dep_atom->dma_fence.dep_count, -1);
/*
* Remove the atom from the list of dma-fence
* waiting atoms.
*/
kbase_dma_fence_waiters_remove(dep_atom);
dep_satisfied = true;
} else {
dep_satisfied = false;
}
#endif /* CONFIG_MALI_DMA_FENCE */
#ifdef CONFIG_KDS
if (dep_atom->kds_dep_satisfied)
dep_satisfied = dep_satisfied && dep_atom->kds_dep_satisfied;
#endif
if (dep_satisfied)
list_add_tail(&dep_atom->dep_item[0], out_list);
}
}
@ -756,6 +886,9 @@ bool jd_submit_atom(struct kbase_context *kctx,
katom->kds_dep_satisfied = true;
katom->kds_rset = NULL;
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
atomic_set(&katom->dma_fence.dep_count, -1);
#endif
/* Don't do anything if there is a mess up with dependencies.
This is done in a separate cycle to check both the dependencies at ones, otherwise
@ -868,11 +1001,23 @@ bool jd_submit_atom(struct kbase_context *kctx,
kbase_tlstream_tl_ret_atom_ctx(katom, kctx);
for (i = 0; i < 2; i++)
if (BASE_JD_DEP_TYPE_INVALID != kbase_jd_katom_dep_type(
&katom->dep[i]))
&katom->dep[i])) {
kbase_tlstream_tl_dep_atom_atom(
(void *)kbase_jd_katom_dep_atom(
&katom->dep[i]),
(void *)katom);
} else if (BASE_JD_DEP_TYPE_INVALID !=
user_atom->pre_dep[i].dependency_type) {
/* Resolved dependency. */
int dep_atom_number =
user_atom->pre_dep[i].atom_id;
struct kbase_jd_atom *dep_atom =
&jctx->atoms[dep_atom_number];
kbase_tlstream_tl_rdep_atom_atom(
(void *)dep_atom,
(void *)katom);
}
/* Reject atoms with job chain = NULL, as these cause issues with soft-stop */
if (!katom->jc && (katom->core_req & BASEP_JD_REQ_ATOM_TYPE) != BASE_JD_REQ_DEP) {
@ -893,6 +1038,17 @@ bool jd_submit_atom(struct kbase_context *kctx,
goto out;
}
/* Reject atoms with invalid core requirements */
if ((katom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) &&
(katom->core_req & BASE_JD_REQ_EVENT_COALESCE)) {
dev_warn(kctx->kbdev->dev,
"Rejecting atom with invalid core requirements");
katom->event_code = BASE_JD_EVENT_JOB_INVALID;
katom->core_req &= ~BASE_JD_REQ_EVENT_COALESCE;
ret = jd_done_nolock(katom, NULL);
goto out;
}
/* For invalid priority, be most lenient and choose the default */
sched_prio = kbasep_js_atom_prio_to_sched_prio(user_atom->prio);
if (sched_prio == KBASE_JS_ATOM_SCHED_PRIO_INVALID)
@ -949,6 +1105,13 @@ bool jd_submit_atom(struct kbase_context *kctx,
}
#endif /* CONFIG_KDS */
#ifdef CONFIG_MALI_DMA_FENCE
if (atomic_read(&katom->dma_fence.dep_count) != -1) {
ret = false;
goto out;
}
#endif /* CONFIG_MALI_DMA_FENCE */
if ((katom->core_req & BASEP_JD_REQ_ATOM_TYPE)
== BASE_JD_REQ_SOFT_REPLAY) {
if (kbase_replay_process(katom))
@ -1522,8 +1685,19 @@ void kbase_jd_zap_context(struct kbase_context *kctx)
}
#endif
#ifdef CONFIG_MALI_DMA_FENCE
kbase_dma_fence_cancel_all_atoms(kctx);
#endif
mutex_unlock(&kctx->jctx.lock);
#ifdef CONFIG_MALI_DMA_FENCE
/* Flush dma-fence workqueue to ensure that any callbacks that may have
* been queued are done before continuing.
*/
flush_workqueue(kctx->dma_fence.wq);
#endif
kbase_jm_wait_for_zero_jobs(kctx);
}
@ -1539,7 +1713,8 @@ int kbase_jd_init(struct kbase_context *kctx)
KBASE_DEBUG_ASSERT(kctx);
kctx->jctx.job_done_wq = alloc_workqueue("mali_jd", 0, 1);
kctx->jctx.job_done_wq = alloc_workqueue("mali_jd",
WQ_HIGHPRI | WQ_UNBOUND, 1);
if (NULL == kctx->jctx.job_done_wq) {
mali_err = -ENOMEM;
goto out1;
@ -1554,6 +1729,12 @@ int kbase_jd_init(struct kbase_context *kctx)
/* Catch userspace attempting to use an atom which doesn't exist as a pre-dependency */
kctx->jctx.atoms[i].event_code = BASE_JD_EVENT_JOB_INVALID;
kctx->jctx.atoms[i].status = KBASE_JD_ATOM_STATE_UNUSED;
#ifdef CONFIG_MALI_DMA_FENCE
kctx->jctx.atoms[i].dma_fence.context = fence_context_alloc(1);
atomic_set(&kctx->jctx.atoms[i].dma_fence.seqno, 0);
INIT_LIST_HEAD(&kctx->jctx.atoms[i].dma_fence.callbacks);
#endif
}
mutex_init(&kctx->jctx.lock);

View File

@ -2665,6 +2665,7 @@ static void js_return_worker(struct work_struct *data)
WARN_ON(!kctx->ctx_runnable_ref);
kctx->ctx_runnable_ref = false;
atomic_dec(&kbdev->js_data.nr_contexts_runnable);
timer_sync = true;
}
if (kctx->as_nr != KBASEP_AS_NR_INVALID &&
@ -2763,6 +2764,7 @@ bool kbase_js_complete_atom_wq(struct kbase_context *kctx,
WARN_ON(!kctx->ctx_runnable_ref);
kctx->ctx_runnable_ref = false;
atomic_dec(&kbdev->js_data.nr_contexts_runnable);
timer_sync = true;
}
}
WARN_ON(katom->atom_flags & KBASE_KATOM_FLAG_JSCTX_IN_LL);

View File

@ -777,7 +777,7 @@ void kbase_free_alloced_region(struct kbase_va_region *reg)
* list should it be there.
*/
kbase_sticky_resource_release(reg->kctx, NULL,
reg->start_pfn << PAGE_SHIFT, true);
reg->start_pfn << PAGE_SHIFT);
kbase_mem_phy_alloc_put(reg->cpu_alloc);
kbase_mem_phy_alloc_put(reg->gpu_alloc);
@ -1309,8 +1309,8 @@ int kbase_alloc_phy_pages_helper(
size_t nr_pages_requested)
{
int new_page_count __maybe_unused;
size_t old_page_count = alloc->nents;
KBASE_DEBUG_ASSERT(alloc);
KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_NATIVE);
KBASE_DEBUG_ASSERT(alloc->imported.kctx);
@ -1326,9 +1326,18 @@ int kbase_alloc_phy_pages_helper(
kbase_process_page_usage_inc(alloc->imported.kctx, nr_pages_requested);
if (kbase_mem_pool_alloc_pages(&alloc->imported.kctx->mem_pool,
nr_pages_requested, alloc->pages + alloc->nents) != 0)
nr_pages_requested, alloc->pages + old_page_count) != 0)
goto no_alloc;
/*
* Request a zone cache update, this scans only the new pages an
* appends their information to the zone cache. if the update
* fails then clear the cache so we fall-back to doing things
* page by page.
*/
if (kbase_zone_cache_update(alloc, old_page_count) != 0)
kbase_zone_cache_clear(alloc);
kbase_tlstream_aux_pagesalloc(
(u32)alloc->imported.kctx->id,
(u64)new_page_count);
@ -1367,6 +1376,14 @@ int kbase_free_phy_pages_helper(
syncback = alloc->properties & KBASE_MEM_PHY_ALLOC_ACCESSED_CACHED;
/*
* Clear the zone cache, we don't expect JIT allocations to be
* shrunk in parts so there is no point trying to optimize for that
* by scanning for the changes caused by freeing this memory and
* updating the existing cache entries.
*/
kbase_zone_cache_clear(alloc);
kbase_mem_pool_free_pages(&kctx->mem_pool,
nr_pages_to_free,
start_free,
@ -1441,6 +1458,8 @@ void kbase_mem_kref_free(struct kref *kref)
break;
#endif
case KBASE_MEM_TYPE_IMPORTED_USER_BUF:
if (alloc->imported.user_buf.mm)
mmdrop(alloc->imported.user_buf.mm);
kfree(alloc->imported.user_buf.pages);
break;
case KBASE_MEM_TYPE_TB:{
@ -1529,6 +1548,10 @@ bool kbase_check_alloc_flags(unsigned long flags)
if ((flags & (BASE_MEM_PROT_GPU_RD | BASE_MEM_PROT_GPU_WR)) == 0)
return false;
/* BASE_MEM_IMPORT_SHARED is only valid for imported memory */
if ((flags & BASE_MEM_IMPORT_SHARED) == BASE_MEM_IMPORT_SHARED)
return false;
return true;
}
@ -1897,7 +1920,8 @@ struct kbase_va_region *kbase_jit_allocate(struct kbase_context *kctx,
} else {
/* No suitable JIT allocation was found so create a new one */
u64 flags = BASE_MEM_PROT_CPU_RD | BASE_MEM_PROT_GPU_RD |
BASE_MEM_PROT_GPU_WR | BASE_MEM_GROW_ON_GPF;
BASE_MEM_PROT_GPU_WR | BASE_MEM_GROW_ON_GPF |
BASE_MEM_COHERENT_LOCAL;
u64 gpu_addr;
u16 alignment;
@ -2031,7 +2055,7 @@ static int kbase_jd_user_buf_map(struct kbase_context *kctx,
long i;
int err = -ENOMEM;
unsigned long address;
struct task_struct *owner;
struct mm_struct *mm;
struct device *dev;
unsigned long offset;
unsigned long local_size;
@ -2039,13 +2063,13 @@ static int kbase_jd_user_buf_map(struct kbase_context *kctx,
alloc = reg->gpu_alloc;
pa = kbase_get_gpu_phy_pages(reg);
address = alloc->imported.user_buf.address;
owner = alloc->imported.user_buf.owner;
mm = alloc->imported.user_buf.mm;
KBASE_DEBUG_ASSERT(alloc->type == KBASE_MEM_TYPE_IMPORTED_USER_BUF);
pages = alloc->imported.user_buf.pages;
pinned_pages = get_user_pages(owner, owner->mm,
pinned_pages = get_user_pages(NULL, mm,
address,
alloc->imported.user_buf.nr_pages,
reg->flags & KBASE_REG_GPU_WR,
@ -2256,7 +2280,7 @@ struct kbase_mem_phy_alloc *kbase_map_external_resource(
/* decide what needs to happen for this resource */
switch (reg->gpu_alloc->type) {
case BASE_MEM_IMPORT_TYPE_USER_BUFFER: {
if (reg->gpu_alloc->imported.user_buf.owner->mm != locked_mm)
if (reg->gpu_alloc->imported.user_buf.mm != locked_mm)
goto exit;
reg->gpu_alloc->imported.user_buf.current_mapping_usage_count++;
@ -2372,7 +2396,7 @@ struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire(
lockdep_assert_held(&kctx->reg_lock);
/*
* Walk the per context externel resource metadata list for the
* Walk the per context external resource metadata list for the
* metadata which matches the region which is being acquired.
*/
list_for_each_entry(walker, &kctx->ext_res_meta_head, ext_res_node) {
@ -2412,14 +2436,8 @@ struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire(
goto fail_map;
meta->gpu_addr = reg->start_pfn << PAGE_SHIFT;
meta->refcount = 1;
list_add(&meta->ext_res_node, &kctx->ext_res_meta_head);
} else {
if (meta->refcount == UINT_MAX)
goto failed;
meta->refcount++;
}
return meta;
@ -2431,16 +2449,17 @@ struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire(
}
bool kbase_sticky_resource_release(struct kbase_context *kctx,
struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr, bool force)
struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr)
{
struct kbase_ctx_ext_res_meta *walker;
struct kbase_va_region *reg;
lockdep_assert_held(&kctx->reg_lock);
/* Search of the metadata if one isn't provided. */
if (!meta) {
/*
* Walk the per context externel resource metadata list for the
* Walk the per context external resource metadata list for the
* metadata which matches the region which is being released.
*/
list_for_each_entry(walker, &kctx->ext_res_meta_head,
@ -2456,22 +2475,14 @@ bool kbase_sticky_resource_release(struct kbase_context *kctx,
if (!meta)
return false;
meta->refcount--;
if ((meta->refcount == 0) || force) {
/*
* Last reference to the metadata, drop the physical memory
* reference and free the metadata.
*/
struct kbase_va_region *reg;
/* Drop the physical memory reference and free the metadata. */
reg = kbase_region_tracker_find_region_enclosing_address(
kctx,
meta->gpu_addr);
reg = kbase_region_tracker_find_region_enclosing_address(
kctx,
meta->gpu_addr);
kbase_unmap_external_resource(kctx, reg, meta->alloc);
list_del(&meta->ext_res_node);
kfree(meta);
}
kbase_unmap_external_resource(kctx, reg, meta->alloc);
list_del(&meta->ext_res_node);
kfree(meta);
return true;
}
@ -2502,6 +2513,6 @@ void kbase_sticky_resource_term(struct kbase_context *kctx)
walker = list_first_entry(&kctx->ext_res_meta_head,
struct kbase_ctx_ext_res_meta, ext_res_node);
kbase_sticky_resource_release(kctx, walker, 0, true);
kbase_sticky_resource_release(kctx, walker, 0);
}
}

View File

@ -131,6 +131,8 @@ struct kbase_mem_phy_alloc {
unsigned long properties;
struct list_head zone_cache;
/* member in union valid based on @a type */
union {
#ifdef CONFIG_UMP
@ -157,7 +159,7 @@ struct kbase_mem_phy_alloc {
unsigned long nr_pages;
struct page **pages;
unsigned int current_mapping_usage_count;
struct task_struct *owner;
struct mm_struct *mm;
dma_addr_t *dma_addrs;
} user_buf;
} imported;
@ -373,6 +375,7 @@ static inline struct kbase_mem_phy_alloc *kbase_alloc_create(size_t nr_pages, en
alloc->pages = (void *)(alloc + 1);
INIT_LIST_HEAD(&alloc->mappings);
alloc->type = type;
INIT_LIST_HEAD(&alloc->zone_cache);
if (type == KBASE_MEM_TYPE_IMPORTED_USER_BUF)
alloc->imported.user_buf.dma_addrs =
@ -989,23 +992,53 @@ struct kbase_ctx_ext_res_meta *kbase_sticky_resource_acquire(
* @kctx: kbase context.
* @meta: Binding metadata.
* @gpu_addr: GPU address of the external resource.
* @force: If the release is being forced.
*
* If meta is NULL then gpu_addr will be used to scan the metadata list and
* find the matching metadata (if any), otherwise the provided meta will be
* used and gpu_addr will be ignored.
*
* If force is true then the refcount in the metadata is ignored and the
* resource will be forced freed.
*
* Return: True if the release found the metadata and the reference was dropped.
*/
bool kbase_sticky_resource_release(struct kbase_context *kctx,
struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr, bool force);
struct kbase_ctx_ext_res_meta *meta, u64 gpu_addr);
/**
* kbase_sticky_resource_term - Terminate sticky resource management.
* @kctx: kbase context
*/
void kbase_sticky_resource_term(struct kbase_context *kctx);
/**
* kbase_zone_cache_update - Update the memory zone cache after new pages have
* been added.
* @alloc: The physical memory allocation to build the cache for.
* @start_offset: Offset to where the new pages start.
*
* Updates an existing memory zone cache, updating the counters for the
* various zones.
* If the memory allocation doesn't already have a zone cache assume that
* one isn't created and thus don't do anything.
*
* Return: Zero cache was updated, negative error code on error.
*/
int kbase_zone_cache_update(struct kbase_mem_phy_alloc *alloc,
size_t start_offset);
/**
* kbase_zone_cache_build - Build the memory zone cache.
* @alloc: The physical memory allocation to build the cache for.
*
* Create a new zone cache for the provided physical memory allocation if
* one doesn't already exist, if one does exist then just return.
*
* Return: Zero if the zone cache was created, negative error code on error.
*/
int kbase_zone_cache_build(struct kbase_mem_phy_alloc *alloc);
/**
* kbase_zone_cache_clear - Clear the memory zone cache.
* @alloc: The physical memory allocation to clear the cache on.
*/
void kbase_zone_cache_clear(struct kbase_mem_phy_alloc *alloc);
#endif /* _KBASE_MEM_H_ */

View File

@ -42,10 +42,7 @@
#include <mali_kbase_mem_linux.h>
#include <mali_kbase_config_defaults.h>
#include <mali_kbase_hwaccess_time.h>
#if defined(CONFIG_MALI_MIPE_ENABLED)
#include <mali_kbase_tlstream.h>
#endif
static int kbase_tracking_page_setup(struct kbase_context *kctx, struct vm_area_struct *vma);
static const struct vm_operations_struct kbase_vm_ops;
@ -519,6 +516,100 @@ void kbase_mem_evictable_deinit(struct kbase_context *kctx)
unregister_shrinker(&kctx->reclaim);
}
struct kbase_mem_zone_cache_entry {
/* List head used to link the cache entry to the memory allocation. */
struct list_head zone_node;
/* The zone the cacheline is for. */
struct zone *zone;
/* The number of pages in the allocation which belong to this zone. */
u64 count;
};
static bool kbase_zone_cache_builder(struct kbase_mem_phy_alloc *alloc,
size_t start_offset)
{
struct kbase_mem_zone_cache_entry *cache = NULL;
size_t i;
int ret = 0;
for (i = start_offset; i < alloc->nents; i++) {
struct page *p = phys_to_page(alloc->pages[i]);
struct zone *zone = page_zone(p);
bool create = true;
if (cache && (cache->zone == zone)) {
/*
* Fast path check as most of the time adjacent
* pages come from the same zone.
*/
create = false;
} else {
/*
* Slow path check, walk all the cache entries to see
* if we already know about this zone.
*/
list_for_each_entry(cache, &alloc->zone_cache, zone_node) {
if (cache->zone == zone) {
create = false;
break;
}
}
}
/* This zone wasn't found in the cache, create an entry for it */
if (create) {
cache = kmalloc(sizeof(*cache), GFP_KERNEL);
if (!cache) {
ret = -ENOMEM;
goto bail;
}
cache->zone = zone;
cache->count = 0;
list_add(&cache->zone_node, &alloc->zone_cache);
}
cache->count++;
}
return 0;
bail:
return ret;
}
int kbase_zone_cache_update(struct kbase_mem_phy_alloc *alloc,
size_t start_offset)
{
/*
* Bail if the zone cache is empty, only update the cache if it
* existed in the first place.
*/
if (list_empty(&alloc->zone_cache))
return 0;
return kbase_zone_cache_builder(alloc, start_offset);
}
int kbase_zone_cache_build(struct kbase_mem_phy_alloc *alloc)
{
/* Bail if the zone cache already exists */
if (!list_empty(&alloc->zone_cache))
return 0;
return kbase_zone_cache_builder(alloc, 0);
}
void kbase_zone_cache_clear(struct kbase_mem_phy_alloc *alloc)
{
struct kbase_mem_zone_cache_entry *walker;
while(!list_empty(&alloc->zone_cache)){
walker = list_first_entry(&alloc->zone_cache,
struct kbase_mem_zone_cache_entry, zone_node);
list_del(&walker->zone_node);
kfree(walker);
}
}
/**
* kbase_mem_evictable_mark_reclaim - Mark the pages as reclaimable.
* @alloc: The physical allocation
@ -526,13 +617,28 @@ void kbase_mem_evictable_deinit(struct kbase_context *kctx)
static void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc)
{
struct kbase_context *kctx = alloc->imported.kctx;
struct kbase_mem_zone_cache_entry *zone_cache;
int __maybe_unused new_page_count;
int i;
int err;
for (i = 0; i < alloc->nents; i++) {
struct page *p = phys_to_page(alloc->pages[i]);
/* Attempt to build a zone cache of tracking */
err = kbase_zone_cache_build(alloc);
if (err == 0) {
/* Bulk update all the zones */
list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) {
zone_page_state_add(zone_cache->count,
zone_cache->zone, NR_SLAB_RECLAIMABLE);
}
} else {
/* Fall-back to page by page updates */
int i;
zone_page_state_add(1, page_zone(p), NR_SLAB_RECLAIMABLE);
for (i = 0; i < alloc->nents; i++) {
struct page *p = phys_to_page(alloc->pages[i]);
struct zone *zone = page_zone(p);
zone_page_state_add(1, zone, NR_SLAB_RECLAIMABLE);
}
}
kbase_process_page_usage_dec(kctx, alloc->nents);
@ -540,11 +646,9 @@ static void kbase_mem_evictable_mark_reclaim(struct kbase_mem_phy_alloc *alloc)
&kctx->used_pages);
kbase_atomic_sub_pages(alloc->nents, &kctx->kbdev->memdev.used_pages);
#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
#endif
}
/**
@ -555,8 +659,9 @@ static
void kbase_mem_evictable_unmark_reclaim(struct kbase_mem_phy_alloc *alloc)
{
struct kbase_context *kctx = alloc->imported.kctx;
struct kbase_mem_zone_cache_entry *zone_cache;
int __maybe_unused new_page_count;
int i;
int err;
new_page_count = kbase_atomic_add_pages(alloc->nents,
&kctx->used_pages);
@ -567,17 +672,29 @@ void kbase_mem_evictable_unmark_reclaim(struct kbase_mem_phy_alloc *alloc)
* then remove it from the reclaimable accounting. */
kbase_process_page_usage_inc(kctx, alloc->nents);
for (i = 0; i < alloc->nents; i++) {
struct page *p = phys_to_page(alloc->pages[i]);
/* Attempt to build a zone cache of tracking */
err = kbase_zone_cache_build(alloc);
if (err == 0) {
/* Bulk update all the zones */
list_for_each_entry(zone_cache, &alloc->zone_cache, zone_node) {
zone_page_state_add(-zone_cache->count,
zone_cache->zone, NR_SLAB_RECLAIMABLE);
}
} else {
/* Fall-back to page by page updates */
int i;
zone_page_state_add(-1, page_zone(p), NR_SLAB_RECLAIMABLE);
for (i = 0; i < alloc->nents; i++) {
struct page *p = phys_to_page(alloc->pages[i]);
struct zone *zone = page_zone(p);
zone_page_state_add(-1, zone, NR_SLAB_RECLAIMABLE);
}
}
#if defined(CONFIG_MALI_MIPE_ENABLED)
kbase_tlstream_aux_pagesalloc(
(u32)kctx->id,
(u64)new_page_count);
#endif
}
int kbase_mem_evictable_make(struct kbase_mem_phy_alloc *gpu_alloc)
@ -894,6 +1011,7 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, in
struct kbase_va_region *reg;
struct dma_buf *dma_buf;
struct dma_buf_attachment *dma_attachment;
bool shared_zone = false;
dma_buf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dma_buf))
@ -914,15 +1032,23 @@ static struct kbase_va_region *kbase_mem_from_umm(struct kbase_context *kctx, in
/* ignore SAME_VA */
*flags &= ~BASE_MEM_SAME_VA;
if (*flags & BASE_MEM_IMPORT_SHARED)
shared_zone = true;
#ifdef CONFIG_64BIT
if (!kctx->is_compat) {
/* 64-bit tasks must MMAP anyway, but not expose this address to clients */
/*
* 64-bit tasks require us to reserve VA on the CPU that we use
* on the GPU.
*/
shared_zone = true;
}
#endif
if (shared_zone) {
*flags |= BASE_MEM_NEED_MMAP;
reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_SAME_VA);
} else {
#else
if (1) {
#endif
reg = kbase_alloc_free_region(kctx, 0, *va_pages, KBASE_REG_ZONE_CUSTOM_VA);
}
@ -989,6 +1115,7 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
struct kbase_va_region *reg;
long faulted_pages;
int zone = KBASE_REG_ZONE_CUSTOM_VA;
bool shared_zone = false;
*va_pages = (PAGE_ALIGN(address + size) >> PAGE_SHIFT) -
PFN_DOWN(address);
@ -1002,14 +1129,24 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
/* SAME_VA generally not supported with imported memory (no known use cases) */
*flags &= ~BASE_MEM_SAME_VA;
if (*flags & BASE_MEM_IMPORT_SHARED)
shared_zone = true;
#ifdef CONFIG_64BIT
if (!kctx->is_compat) {
/* 64-bit tasks must MMAP anyway, but not expose this address to
* clients */
/*
* 64-bit tasks require us to reserve VA on the CPU that we use
* on the GPU.
*/
shared_zone = true;
}
#endif
if (shared_zone) {
*flags |= BASE_MEM_NEED_MMAP;
zone = KBASE_REG_ZONE_SAME_VA;
}
#endif
reg = kbase_alloc_free_region(kctx, 0, *va_pages, zone);
if (!reg)
@ -1059,7 +1196,8 @@ static struct kbase_va_region *kbase_mem_from_user_buffer(
reg->gpu_alloc->imported.user_buf.nr_pages = faulted_pages;
reg->gpu_alloc->imported.user_buf.pages = kmalloc_array(faulted_pages,
sizeof(struct page *), GFP_KERNEL);
reg->gpu_alloc->imported.user_buf.owner = current;
reg->gpu_alloc->imported.user_buf.mm = current->mm;
atomic_inc(&current->mm->mm_count);
if (!reg->gpu_alloc->imported.user_buf.pages)
goto no_page_array;
@ -1576,7 +1714,7 @@ int kbase_mem_commit(struct kbase_context *kctx, u64 gpu_addr, u64 new_pages, en
goto out_unlock;
}
/* can't grow regions which are ephemeral */
if (reg->flags & BASE_MEM_DONT_NEED) {
if (reg->flags & KBASE_REG_DONT_NEED) {
*failure_reason = BASE_BACKING_THRESHOLD_ERROR_NOT_GROWABLE;
goto out_unlock;
}

View File

@ -264,6 +264,8 @@ static size_t kbase_mem_pool_grow(struct kbase_mem_pool *pool,
for (i = 0; i < nr_to_grow && !kbase_mem_pool_is_full(pool); i++) {
p = kbase_mem_pool_alloc_page(pool);
if (!p)
break;
kbase_mem_pool_add(pool, p);
}

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2014 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2014, 2016 ARM Limited. All rights reserved.
*
* This program is 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,9 +23,6 @@
#include <linux/platform_device.h>
#include <linux/string.h>
#ifdef CONFIG_MACH_MANTA
#include <plat/devs.h>
#endif
/*
* This file is included only for type definitions and functions belonging to
@ -62,6 +59,7 @@ static void kbasep_config_parse_io_resources(const struct kbase_io_resources *io
linux_resources[0].start = io_resources->io_memory_region.start;
linux_resources[0].end = io_resources->io_memory_region.end;
linux_resources[0].flags = IORESOURCE_MEM;
linux_resources[1].start = io_resources->job_irq_number;
linux_resources[1].end = io_resources->job_irq_number;
linux_resources[1].flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL;

View File

@ -799,13 +799,33 @@ static int kbasep_replay_parse_payload(struct kbase_context *kctx,
f_atom->core_req = payload->fragment_core_req | BASEP_JD_REQ_EVENT_NEVER;
/* Sanity check core requirements*/
if ((t_atom->core_req & BASEP_JD_REQ_ATOM_TYPE &
if (unlikely((t_atom->core_req & BASEP_JD_REQ_ATOM_TYPE &
~BASE_JD_REQ_COHERENT_GROUP) != BASE_JD_REQ_T ||
(f_atom->core_req & BASEP_JD_REQ_ATOM_TYPE &
~BASE_JD_REQ_COHERENT_GROUP) != BASE_JD_REQ_FS ||
~BASE_JD_REQ_COHERENT_GROUP & ~BASE_JD_REQ_FS_AFBC) != BASE_JD_REQ_FS ||
t_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES ||
f_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES) {
dev_err(kctx->kbdev->dev, "Invalid core requirements\n");
f_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES)) {
int t_atom_type = t_atom->core_req & BASEP_JD_REQ_ATOM_TYPE & ~BASE_JD_REQ_COHERENT_GROUP;
int f_atom_type = f_atom->core_req & BASEP_JD_REQ_ATOM_TYPE & ~BASE_JD_REQ_COHERENT_GROUP & ~BASE_JD_REQ_FS_AFBC;
int t_has_ex_res = t_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES;
int f_has_ex_res = f_atom->core_req & BASE_JD_REQ_EXTERNAL_RESOURCES;
if (t_atom_type != BASE_JD_REQ_T) {
dev_err(kctx->kbdev->dev, "Invalid core requirement: Tiler atom not a tiler job. Was: 0x%x\n Expected: 0x%x",
t_atom_type, BASE_JD_REQ_T);
}
if (f_atom_type != BASE_JD_REQ_FS) {
dev_err(kctx->kbdev->dev, "Invalid core requirement: Fragment shader atom not a fragment shader. Was 0x%x Expected: 0x%x\n",
f_atom_type, BASE_JD_REQ_FS);
}
if (t_has_ex_res) {
dev_err(kctx->kbdev->dev, "Invalid core requirement: Tiler atom has external resources.\n");
}
if (f_has_ex_res) {
dev_err(kctx->kbdev->dev, "Invalid core requirement: Fragment shader atom has external resources.\n");
}
goto out;
}

View File

@ -19,6 +19,10 @@
#include <mali_kbase.h>
#if defined(CONFIG_DMA_SHARED_BUFFER)
#include <linux/dma-buf.h>
#include <asm/cacheflush.h>
#endif /* defined(CONFIG_DMA_SHARED_BUFFER) */
#include <linux/dma-mapping.h>
#ifdef CONFIG_SYNC
#include "sync.h"
@ -528,12 +532,35 @@ static void kbasep_soft_event_cancel_job(struct kbase_jd_atom *katom)
}
struct kbase_debug_copy_buffer {
u64 size;
size_t size;
struct page **pages;
int nr_pages;
u64 offset;
size_t offset;
/*To find memory region*/
u64 gpu_addr;
struct page **extres_pages;
int nr_extres_pages;
};
static inline void free_user_buffer(struct kbase_debug_copy_buffer *buffer)
{
struct page **pages = buffer->extres_pages;
int nr_pages = buffer->nr_extres_pages;
if (pages) {
int i;
for (i = 0; i < nr_pages; i++) {
struct page *pg = pages[i];
if (pg)
put_page(pg);
}
kfree(pages);
}
}
static void kbase_debug_copy_finish(struct kbase_jd_atom *katom)
{
struct kbase_debug_copy_buffer *buffers =
@ -544,8 +571,13 @@ static void kbase_debug_copy_finish(struct kbase_jd_atom *katom)
if (!buffers)
return;
kbase_gpu_vm_lock(katom->kctx);
for (i = 0; i < nr; i++) {
int p;
struct kbase_va_region *reg;
reg = kbase_region_tracker_find_region_enclosing_address(
katom->kctx, buffers[i].gpu_addr);
if (!buffers[i].pages)
break;
@ -556,7 +588,21 @@ static void kbase_debug_copy_finish(struct kbase_jd_atom *katom)
put_page(pg);
}
kfree(buffers[i].pages);
if (reg && reg->gpu_alloc) {
switch (reg->gpu_alloc->type) {
case BASE_MEM_IMPORT_TYPE_USER_BUFFER:
{
free_user_buffer(&buffers[i]);
break;
}
default:
/* Nothing to be done. */
break;
}
kbase_mem_phy_alloc_put(reg->gpu_alloc);
}
}
kbase_gpu_vm_unlock(katom->kctx);
kfree(buffers);
katom->jc = 0;
@ -574,7 +620,7 @@ static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom)
if (!user_structs)
return -EINVAL;
buffers = kmalloc_array(nr, sizeof(*buffers), GFP_KERNEL);
buffers = kcalloc(nr, sizeof(*buffers), GFP_KERNEL);
if (!buffers) {
ret = -ENOMEM;
katom->jc = 0;
@ -589,13 +635,11 @@ static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom)
goto out_cleanup;
}
if (copy_from_user(user_buffers, user_structs,
sizeof(*user_buffers)*nr)) {
ret = -EINVAL;
ret = copy_from_user(user_buffers, user_structs,
sizeof(*user_buffers)*nr);
if (ret)
goto out_cleanup;
}
down_read(&current->mm->mmap_sem);
for (i = 0; i < nr; i++) {
u64 addr = user_buffers[i].address;
u64 page_addr = addr & PAGE_MASK;
@ -603,47 +647,109 @@ static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom)
u64 last_page_addr = end_page_addr & PAGE_MASK;
int nr_pages = (last_page_addr-page_addr)/PAGE_SIZE+1;
int pinned_pages;
struct kbase_va_region *reg;
struct base_external_resource user_extres;
if (!user_buffers[i].address) {
memset(&buffers[i], 0,
sizeof(struct kbase_debug_copy_buffer));
if (!addr)
continue;
}
buffers[i].nr_pages = nr_pages;
buffers[i].offset = addr & ~PAGE_MASK;
if (buffers[i].offset >= PAGE_SIZE) {
ret = -EINVAL;
goto out_cleanup;
}
buffers[i].size = user_buffers[i].size;
buffers[i].pages = kcalloc(nr_pages, sizeof(struct page *),
GFP_KERNEL);
if (!buffers[i].pages) {
ret = -ENOMEM;
goto out_unlock;
goto out_cleanup;
}
pinned_pages = get_user_pages(current, current->mm, page_addr,
pinned_pages = get_user_pages_fast(page_addr,
nr_pages,
1, /* Write */
0, /* No force */
buffers[i].pages,
NULL);
buffers[i].pages);
if (pinned_pages < 0) {
ret = pinned_pages;
goto out_unlock;
goto out_cleanup;
}
if (pinned_pages != nr_pages) {
ret = -EINVAL;
goto out_cleanup;
}
user_extres = user_buffers[i].extres;
if (user_extres.ext_resource == 0ULL) {
ret = -EINVAL;
goto out_cleanup;
}
buffers[i].gpu_addr = user_extres.ext_resource &
~BASE_EXT_RES_ACCESS_EXCLUSIVE;
kbase_gpu_vm_lock(katom->kctx);
reg = kbase_region_tracker_find_region_enclosing_address(
katom->kctx, buffers[i].gpu_addr);
if (NULL == reg || NULL == reg->cpu_alloc ||
(reg->flags & KBASE_REG_FREE)) {
ret = -EINVAL;
goto out_unlock;
}
}
up_read(&current->mm->mmap_sem);
kbase_mem_phy_alloc_get(reg->gpu_alloc);
buffers[i].nr_extres_pages = reg->nr_pages;
if (reg->nr_pages*PAGE_SIZE != buffers[i].size)
dev_warn(katom->kctx->kbdev->dev, "Copy buffer is not of same size as the external resource to copy.\n");
switch (reg->gpu_alloc->type) {
case BASE_MEM_IMPORT_TYPE_USER_BUFFER:
{
struct kbase_mem_phy_alloc *alloc = reg->gpu_alloc;
unsigned long nr_pages =
alloc->imported.user_buf.nr_pages;
if (alloc->imported.user_buf.mm != current->mm) {
ret = -EINVAL;
goto out_unlock;
}
buffers[i].extres_pages = kcalloc(nr_pages,
sizeof(struct page *), GFP_KERNEL);
if (!buffers[i].extres_pages) {
ret = -ENOMEM;
goto out_unlock;
}
ret = get_user_pages_fast(
alloc->imported.user_buf.address,
nr_pages, 0,
buffers[i].extres_pages);
if (ret != nr_pages)
goto out_unlock;
ret = 0;
break;
}
case BASE_MEM_IMPORT_TYPE_UMP:
{
dev_warn(katom->kctx->kbdev->dev,
"UMP is not supported for debug_copy jobs\n");
ret = -EINVAL;
goto out_unlock;
}
default:
/* Nothing to be done. */
break;
}
kbase_gpu_vm_unlock(katom->kctx);
}
kfree(user_buffers);
return ret;
out_unlock:
up_read(&current->mm->mmap_sem);
kbase_gpu_vm_unlock(katom->kctx);
out_cleanup:
kfree(buffers);
@ -652,10 +758,135 @@ static int kbase_debug_copy_prepare(struct kbase_jd_atom *katom)
/* Frees allocated memory for kbase_debug_copy_job struct, including
* members, and sets jc to 0 */
kbase_debug_copy_finish(katom);
return ret;
}
static 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)
{
void *target_page = kmap(pages[*target_page_nr]);
size_t chunk = PAGE_SIZE-offset;
if (!target_page) {
*target_page_nr += 1;
dev_warn(kctx->kbdev->dev, "kmap failed in debug_copy job.");
return;
}
chunk = min(chunk, *to_copy);
memcpy(target_page + offset, extres_page, chunk);
*to_copy -= chunk;
kunmap(pages[*target_page_nr]);
*target_page_nr += 1;
if (*target_page_nr >= nr_pages)
return;
target_page = kmap(pages[*target_page_nr]);
if (!target_page) {
*target_page_nr += 1;
dev_warn(kctx->kbdev->dev, "kmap failed in debug_copy job.");
return;
}
KBASE_DEBUG_ASSERT(target_page);
chunk = min(offset, *to_copy);
memcpy(target_page, extres_page + PAGE_SIZE-offset, chunk);
*to_copy -= chunk;
kunmap(pages[*target_page_nr]);
}
static int kbase_mem_copy_from_extres(struct kbase_context *kctx,
struct kbase_debug_copy_buffer *buf_data)
{
unsigned int i;
unsigned int target_page_nr = 0;
struct kbase_va_region *reg;
struct page **pages = buf_data->pages;
u64 offset = buf_data->offset;
size_t extres_size = buf_data->nr_extres_pages*PAGE_SIZE;
size_t to_copy = min(extres_size, buf_data->size);
int ret = 0;
KBASE_DEBUG_ASSERT(pages != NULL);
kbase_gpu_vm_lock(kctx);
reg = kbase_region_tracker_find_region_enclosing_address(
kctx, buf_data->gpu_addr);
if (!reg) {
ret = -EINVAL;
goto out_unlock;
}
switch (reg->gpu_alloc->type) {
case BASE_MEM_IMPORT_TYPE_USER_BUFFER:
{
for (i = 0; i < buf_data->nr_extres_pages; i++) {
struct page *pg = buf_data->extres_pages[i];
void *extres_page = kmap(pg);
if (extres_page)
kbase_mem_copy_from_extres_page(kctx,
extres_page, pages,
buf_data->nr_pages,
&target_page_nr,
offset, &to_copy);
kunmap(pg);
if (target_page_nr >= buf_data->nr_pages)
break;
}
break;
}
break;
#ifdef CONFIG_DMA_SHARED_BUFFER
case BASE_MEM_IMPORT_TYPE_UMM: {
struct dma_buf *dma_buf = reg->gpu_alloc->imported.umm.dma_buf;
KBASE_DEBUG_ASSERT(dma_buf != NULL);
ret = dma_buf_begin_cpu_access(dma_buf, 0,
buf_data->nr_extres_pages*PAGE_SIZE,
DMA_FROM_DEVICE);
if (ret)
goto out_unlock;
for (i = 0; i < buf_data->nr_extres_pages; i++) {
void *extres_page = dma_buf_kmap(dma_buf, i);
if (extres_page)
kbase_mem_copy_from_extres_page(kctx,
extres_page, pages,
buf_data->nr_pages,
&target_page_nr,
offset, &to_copy);
dma_buf_kunmap(dma_buf, i, extres_page);
if (target_page_nr >= buf_data->nr_pages)
break;
}
dma_buf_end_cpu_access(dma_buf, 0,
buf_data->nr_extres_pages*PAGE_SIZE,
DMA_FROM_DEVICE);
break;
}
#endif
default:
ret = -EINVAL;
}
out_unlock:
kbase_gpu_vm_unlock(kctx);
return ret;
}
static int kbase_debug_copy(struct kbase_jd_atom *katom)
{
struct kbase_debug_copy_buffer *buffers =
@ -663,32 +894,10 @@ static int kbase_debug_copy(struct kbase_jd_atom *katom)
unsigned int i;
for (i = 0; i < katom->nr_extres; i++) {
u64 offset = buffers[i].offset;
u64 buffer_space = buffers[i].size;
int p;
int res = kbase_mem_copy_from_extres(katom->kctx, &buffers[i]);
for (p = 0; p < buffers[i].nr_pages; p++) {
struct page *pg = buffers[i].pages[p];
void *kpage = kmap(pg);
u64 page_space = PAGE_SIZE-offset;
u64 space;
if (page_space <= buffer_space)
space = page_space;
else
space = buffer_space;
/* Temporary - GPUCORE-1843 covers the implementation
* of the actual copying. */
memset(kpage+offset, 0x4B, space);
if (!PageReserved(pg))
SetPageDirty(pg);
kunmap(pg);
offset = 0;
buffer_space -= space;
}
if (res)
return res;
}
return 0;
@ -698,7 +907,6 @@ static int kbase_jit_allocate_prepare(struct kbase_jd_atom *katom)
{
__user void *data = (__user void *)(uintptr_t) katom->jc;
struct base_jit_alloc_info *info;
struct kbase_context *kctx = katom->kctx;
int ret;
/* Fail the job if there is no info structure */
@ -719,15 +927,12 @@ static int kbase_jit_allocate_prepare(struct kbase_jd_atom *katom)
goto free_info;
}
/* If the ID is zero or is in use then fail the job */
if ((info->id == 0) || (kctx->jit_alloc[info->id])) {
/* If the ID is zero then fail the job */
if (info->id == 0) {
ret = -EINVAL;
goto free_info;
}
/* Set the jit_alloc to a non-zero value so we know the ID is in use */
kctx->jit_alloc[info->id] = (struct kbase_va_region *) -1;
/* Sanity check that the PA fits within the VA */
if (info->va_pages < info->commit_pages) {
ret = -EINVAL;
@ -773,6 +978,18 @@ static void kbase_jit_allocate_process(struct kbase_jd_atom *katom)
info = (struct base_jit_alloc_info *) (uintptr_t) katom->jc;
/* The JIT ID is still in use so fail the allocation */
if (kctx->jit_alloc[info->id]) {
katom->event_code = BASE_JD_EVENT_MEM_GROWTH_FAILED;
return;
}
/*
* Mark the allocation so we know it's in use even if the
* allocation itself fails.
*/
kctx->jit_alloc[info->id] = (struct kbase_va_region *) -1;
/* Create a JIT allocation */
reg = kbase_jit_allocate(kctx, info);
if (!reg) {
@ -924,7 +1141,7 @@ static void kbase_ext_res_process(struct kbase_jd_atom *katom, bool map)
goto failed_loop;
} else
if (!kbase_sticky_resource_release(katom->kctx, NULL,
gpu_addr, false))
gpu_addr))
failed = true;
}
@ -949,8 +1166,7 @@ static void kbase_ext_res_process(struct kbase_jd_atom *katom, bool map)
gpu_addr = ext_res->ext_res[i].ext_resource &
~BASE_EXT_RES_ACCESS_EXCLUSIVE;
kbase_sticky_resource_release(katom->kctx, NULL, gpu_addr,
false);
kbase_sticky_resource_release(katom->kctx, NULL, gpu_addr);
}
katom->event_code = BASE_JD_EVENT_JOB_INVALID;
@ -996,7 +1212,13 @@ int kbase_process_soft_job(struct kbase_jd_atom *katom)
kbasep_soft_event_update(katom, BASE_JD_SOFT_EVENT_RESET);
break;
case BASE_JD_REQ_SOFT_DEBUG_COPY:
return kbase_debug_copy(katom);
{
int res = kbase_debug_copy(katom);
if (res)
katom->event_code = BASE_JD_EVENT_JOB_INVALID;
break;
}
case BASE_JD_REQ_SOFT_JIT_ALLOC:
kbase_jit_allocate_process(katom);
break;

View File

@ -0,0 +1,23 @@
/*
*
* (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "mali_kbase_strings.h"
#define KBASE_DRV_NAME "mali"
#define KBASE_TIMELINE_NAME KBASE_DRV_NAME ".timeline"
const char kbase_drv_name[] = KBASE_DRV_NAME;
const char kbase_timeline_name[] = KBASE_TIMELINE_NAME;

View File

@ -0,0 +1,19 @@
/*
*
* (C) COPYRIGHT 2010-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
extern const char kbase_drv_name[];
extern const char kbase_timeline_name[];

View File

@ -140,6 +140,8 @@ enum tl_msg_id_obj {
KBASE_TL_RET_ATOM_AS,
KBASE_TL_NRET_ATOM_AS,
KBASE_TL_DEP_ATOM_ATOM,
KBASE_TL_NDEP_ATOM_ATOM,
KBASE_TL_RDEP_ATOM_ATOM,
KBASE_TL_ATTRIB_ATOM_CONFIG,
KBASE_TL_ATTRIB_AS_CONFIG,
@ -407,6 +409,20 @@ static const struct tp_desc tp_desc_obj[] = {
"@pp",
"atom1,atom2"
},
{
KBASE_TL_NDEP_ATOM_ATOM,
__stringify(KBASE_TL_NDEP_ATOM_ATOM),
"atom2 no longer depends on atom1",
"@pp",
"atom1,atom2"
},
{
KBASE_TL_RDEP_ATOM_ATOM,
__stringify(KBASE_TL_RDEP_ATOM_ATOM),
"resolved dependecy of atom2 depending on atom1",
"@pp",
"atom1,atom2"
},
{
KBASE_TL_ATTRIB_ATOM_CONFIG,
__stringify(KBASE_TL_ATTRIB_ATOM_CONFIG),
@ -1790,6 +1806,56 @@ void __kbase_tlstream_tl_dep_atom_atom(void *atom1, void *atom2)
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
}
void __kbase_tlstream_tl_ndep_atom_atom(void *atom1, void *atom2)
{
const u32 msg_id = KBASE_TL_NDEP_ATOM_ATOM;
const size_t msg_size =
sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2);
unsigned long flags;
char *buffer;
size_t pos = 0;
buffer = kbasep_tlstream_msgbuf_acquire(
TL_STREAM_TYPE_OBJ,
msg_size, &flags);
KBASE_DEBUG_ASSERT(buffer);
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
pos = kbasep_tlstream_write_timestamp(buffer, pos);
pos = kbasep_tlstream_write_bytes(
buffer, pos, &atom1, sizeof(atom1));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &atom2, sizeof(atom2));
KBASE_DEBUG_ASSERT(msg_size == pos);
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
}
void __kbase_tlstream_tl_rdep_atom_atom(void *atom1, void *atom2)
{
const u32 msg_id = KBASE_TL_RDEP_ATOM_ATOM;
const size_t msg_size =
sizeof(msg_id) + sizeof(u64) + sizeof(atom1) + sizeof(atom2);
unsigned long flags;
char *buffer;
size_t pos = 0;
buffer = kbasep_tlstream_msgbuf_acquire(
TL_STREAM_TYPE_OBJ,
msg_size, &flags);
KBASE_DEBUG_ASSERT(buffer);
pos = kbasep_tlstream_write_bytes(buffer, pos, &msg_id, sizeof(msg_id));
pos = kbasep_tlstream_write_timestamp(buffer, pos);
pos = kbasep_tlstream_write_bytes(
buffer, pos, &atom1, sizeof(atom1));
pos = kbasep_tlstream_write_bytes(
buffer, pos, &atom2, sizeof(atom2));
KBASE_DEBUG_ASSERT(msg_size == pos);
kbasep_tlstream_msgbuf_release(TL_STREAM_TYPE_OBJ, flags);
}
void __kbase_tlstream_tl_nret_atom_lpu(void *atom, void *lpu)
{
const u32 msg_id = KBASE_TL_NRET_ATOM_LPU;

View File

@ -124,6 +124,8 @@ void __kbase_tlstream_tl_nret_as_ctx(void *as, void *ctx);
void __kbase_tlstream_tl_ret_atom_as(void *atom, void *as);
void __kbase_tlstream_tl_nret_atom_as(void *atom, void *as);
void __kbase_tlstream_tl_dep_atom_atom(void *atom1, void *atom2);
void __kbase_tlstream_tl_ndep_atom_atom(void *atom1, void *atom2);
void __kbase_tlstream_tl_rdep_atom_atom(void *atom1, void *atom2);
void __kbase_tlstream_tl_attrib_atom_config(
void *atom, u64 jd, u64 affinity, u32 config);
void __kbase_tlstream_tl_attrib_as_config(
@ -393,6 +395,28 @@ extern atomic_t kbase_tlstream_enabled;
#define kbase_tlstream_tl_dep_atom_atom(atom1, atom2) \
__TRACE_IF_ENABLED(tl_dep_atom_atom, atom1, atom2)
/**
* kbase_tlstream_tl_ndep_atom_atom - dependency between atoms resolved
* @atom1: name of the child atom object
* @atom2: name of the parent atom object that depended on child atom
*
* Function emits a timeline message informing that parent atom execution
* dependency on child atom has been resolved.
*/
#define kbase_tlstream_tl_ndep_atom_atom(atom1, atom2) \
__TRACE_IF_ENABLED(tl_ndep_atom_atom, atom1, atom2)
/**
* kbase_tlstream_tl_rdep_atom_atom - information about already resolved dependency between atoms
* @atom1: name of the child atom object
* @atom2: name of the parent atom object that depended on child atom
*
* Function emits a timeline message informing that parent atom execution
* dependency on child atom has been resolved.
*/
#define kbase_tlstream_tl_rdep_atom_atom(atom1, atom2) \
__TRACE_IF_ENABLED(tl_rdep_atom_atom, atom1, atom2)
/**
* kbase_tlstream_tl_attrib_atom_config - atom job slot attributes
* @atom: name of the atom object

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -213,7 +213,6 @@ void kbasep_trace_timeline_debugfs_init(struct kbase_device *kbdev);
js, _producerof_atom_number_completed); \
} while (0)
/** Trace beginning/end of a call to kbase_pm_check_transitions_nolock from a
* certin caller */
#define KBASE_TIMELINE_PM_CHECKTRANS(kbdev, trace_code) \
@ -319,7 +318,6 @@ void kbase_timeline_pm_l2_transition_done(struct kbase_device *kbdev);
#define KBASE_TIMELINE_CONTEXT_ACTIVE(kbdev, count) CSTD_NOP()
static inline void kbase_timeline_job_slot_submit(struct kbase_device *kbdev, struct kbase_context *kctx,
struct kbase_jd_atom *katom, int js)
{

View File

@ -441,9 +441,10 @@ static struct kbase_vinstr_client *kbasep_vinstr_attach_client(
struct kbase_vinstr_client *cli;
KBASE_DEBUG_ASSERT(vinstr_ctx);
KBASE_DEBUG_ASSERT(buffer_count >= 0);
KBASE_DEBUG_ASSERT(buffer_count <= MAX_BUFFER_COUNT);
KBASE_DEBUG_ASSERT(!(buffer_count & (buffer_count - 1)));
if (buffer_count > MAX_BUFFER_COUNT
|| (buffer_count & (buffer_count - 1)))
return NULL;
cli = kzalloc(sizeof(*cli), GFP_KERNEL);
if (!cli)
@ -497,7 +498,7 @@ static struct kbase_vinstr_client *kbasep_vinstr_attach_client(
/* Allocate required number of dumping buffers. */
cli->dump_buffers = (char *)__get_free_pages(
GFP_KERNEL,
GFP_KERNEL | __GFP_ZERO,
get_order(cli->dump_size * cli->buffer_count));
if (!cli->dump_buffers)
goto error;
@ -1517,7 +1518,8 @@ static int kbasep_vinstr_hwcnt_reader_mmap(struct file *filp,
struct vm_area_struct *vma)
{
struct kbase_vinstr_client *cli;
size_t size;
unsigned long size, addr, pfn, offset;
unsigned long vm_size = vma->vm_end - vma->vm_start;
KBASE_DEBUG_ASSERT(filp);
KBASE_DEBUG_ASSERT(vma);
@ -1526,14 +1528,24 @@ static int kbasep_vinstr_hwcnt_reader_mmap(struct file *filp,
KBASE_DEBUG_ASSERT(cli);
size = cli->buffer_count * cli->dump_size;
if (vma->vm_end - vma->vm_start > size)
return -ENOMEM;
if (vma->vm_pgoff > (size >> PAGE_SHIFT))
return -EINVAL;
if (vm_size > size)
return -EINVAL;
offset = vma->vm_pgoff << PAGE_SHIFT;
if ((vm_size + offset) > size)
return -EINVAL;
addr = __pa((unsigned long)cli->dump_buffers + offset);
pfn = addr >> PAGE_SHIFT;
return remap_pfn_range(
vma,
vma->vm_start,
__pa((unsigned long)cli->dump_buffers) >> PAGE_SHIFT,
size,
pfn,
vm_size,
vma->vm_page_prot);
}

View File

@ -567,5 +567,4 @@
/* End TILER_CONFIG register */
#endif /* _MIDGARD_REGMAP_H_ */

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2012-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2012-2016 ARM Limited. All rights reserved.
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
@ -386,7 +386,6 @@ TRACE_EVENT(mali_timeline_context_active,
__entry->count)
);
#endif /* _MALI_TIMELINE_H */
#undef TRACE_INCLUDE_PATH

View File

@ -1,6 +1,6 @@
/*
*
* (C) COPYRIGHT 2011-2015 ARM Limited. All rights reserved.
* (C) COPYRIGHT 2011-2016 ARM Limited. All rights reserved.
*
* This program is 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

@ -44,8 +44,7 @@ kbase_src = [Glob('#kernel/drivers/gpu/arm/midgard/*.c'),
Glob('#kernel/drivers/gpu/arm/midgard/K*'))
]
kbase_src += [Glob('#kernel/drivers/gpu/arm/midgard/internal/*/*.c'),
Glob('#kernel/drivers/gpu/arm/midgard/internal/*/*/*.c')]
kbase_src += [Glob('#kernel/drivers/gpu/arm/midgard/internal/*/*.c')]
if Glob('#kernel/drivers/gpu/arm/midgard/tests/internal/src/mock') and env['unit'] == '1':
kbase_src += [Glob('#kernel/drivers/gpu/arm/midgard/tests/internal/src/mock/*.c')]
@ -123,10 +122,6 @@ if env['os'] != 'android':
if int(env['ump']) == 1:
env.Depends('$STATIC_LIB_PATH/mali_kbase.ko', '$STATIC_LIB_PATH/ump.ko')
if Glob('internal/sconsfrag'):
execfile('internal/sconsfrag')
get_internal(env)
env.KernelObjTarget('kbase', cmd)
env.AppendUnique(BASE=['cutils_linked_list'])